
(load-relative "loadtest.rktl")

(Section 'numbers)

(require racket/extflonum racket/random racket/list)

(define has-single-flonum? (single-flonum-available?))
(define has-exact-zero-inexact-complex? (not (eq? 'chez-scheme (system-type 'vm))))

(test #f number? 'a)
(test #f complex? 'a)
(test #f real? 'a)
(test #f rational? 'a)
(test #f integer? 'a)

(test #t number? 3)
(test #t complex? 3)
(test #t real? 3)
(test #t rational? 3)
(test #t integer? 3)

(test #t number? 3.0)
(test #t complex? 3.0)
(test #t real? 3.0)
(test #t rational? 3.0)
(test #t integer? 3.0)

(test #t number? 3.1)
(test #t complex? 3.1)
(test #t real? 3.1)
(test #t rational? 3.1)
(test #f integer? 3.1)

(test #t number? 3/2)
(test #t complex? 3/2)
(test #t real? 3/2)
(test #t rational? 3/2)
(test #f integer? 3/2)

(test #t number? 3+i)
(test #t complex? 3+i)
(test #f real? 3+i)
(test #f rational? 3+i)
(test #f integer? 3+i)

(test #t number? 3.0+0i)
(test #t complex? 3.0+0i)
(test #t real? 3.0+0i)
(test #t rational? 3.0+0i)
(test #t integer? 3.0+0i)

(test #t number? 3.0+0.0i)
(test #t complex? 3.0+0.0i)
(test #f real? 3.0+0.0i)
(test #f rational? 3.0+0.0i)
(test #f integer? 3.0+0.0i)

(test #t number? 3.1+0.0i)
(test #t complex? 3.1+0.0i)
(test #f real? 3.1+0.0i)
(test #f rational? 3.1+0.0i)
(test #f integer? 3.1+0.0i)

(test #t exact? 3)
(test #t exact? 3/4)
(test #f exact? 3.0)
(test #t exact? (expt 2 100))
(test #t exact? 3+4i)
(test #f exact? 3.0+4i)

(test #f inexact? 3)
(test #f inexact? 3/4)
(test #t inexact? 3.0)
(test #f inexact? (expt 2 100))
(test #f inexact? 3+4i)
(test #t inexact? 3.0+4i)
(test #t inexact? 0+4.0i)
(test #t inexact? 4+0.i)

(test #t flonum? 1.2)
(test #f single-flonum? 1.2)
(test #t flonum? 1.2e3)
(test #f single-flonum? 1.2e3)
#reader "maybe-single.rkt"
(begin
  (test (not has-single-flonum?) flonum? 1.2f3)
  (test has-single-flonum? single-flonum? 1.2f3))

(test #t complex? -4.242154731064108e-5-6.865001427422244e-5i)
(test #f exact? -4.242154731064108e-5-6.865001427422244e-5i)
(test #t inexact? -4.242154731064108e-5-6.865001427422244e-5i)

(test #t complex? -4.242154731064108f-5-6.865001427422244f-5i)
(test #f exact? -4.242154731064108f-5-6.865001427422244f-5i)
(test #t inexact? -4.242154731064108f-5-6.865001427422244f-5i)

(test #t number? +inf.0)
(test #t complex? +inf.0)
(test #t real? +inf.0)
(test #f rational? +inf.0)
(test #f integer? +inf.0)
(test #t flonum? +inf.0)
(test #f single-flonum? +inf.0)

(test #t number? -inf.0)
(test #t complex? -inf.0)
(test #t real? -inf.0)
(test #f rational? -inf.0)
(test #f integer? -inf.0)
(test #t flonum? -inf.0)
(test #f single-flonum? -inf.0)

(test #t number? +nan.0)
(test #t complex? +nan.0)
(test #t real? +nan.0)
(test #f rational? +nan.0)
(test #f integer? +nan.0)
(test #t flonum? +nan.0)
(test #f single-flonum? +nan.0)

(test #t number? +inf.f)
(test #t complex? +inf.f)
(test #t real? +inf.f)
(test #f rational? +inf.f)
(test #f integer? +inf.f)
#reader "maybe-single.rkt"
(begin
  (test (not has-single-flonum?) flonum? +inf.f)
  (test has-single-flonum? single-flonum? +inf.f))

(test #t number? -inf.f)
(test #t complex? -inf.f)
(test #t real? -inf.f)
(test #f rational? -inf.f)
(test #f integer? -inf.f)
#reader "maybe-single.rkt"
(begin
  (test (not has-single-flonum?) flonum? -inf.f)
  (test has-single-flonum? single-flonum? -inf.f))

(test #t number? +nan.f)
(test #t complex? +nan.f)
(test #t real? +nan.f)
(test #f rational? +nan.f)
(test #f integer? +nan.f)
#reader "maybe-single.rkt"
(begin
  (test (not has-single-flonum?) flonum? +nan.f)
  (test has-single-flonum? single-flonum? +nan.f))

(test #t number? -nan.f)
(test #t complex? -nan.f)
(test #t real? -nan.f)
(test #f rational? -nan.f)
(test #f integer? -nan.f)
#reader "maybe-single.rkt"
(begin
  (test (not has-single-flonum?) flonum? -nan.f)
  (test has-single-flonum? single-flonum? -nan.f))

(arity-test inexact? 1 1)
(arity-test number? 1 1)
(arity-test complex? 1 1)
(arity-test real? 1 1)
(arity-test rational? 1 1)
(arity-test integer? 1 1)
(arity-test exact? 1 1)
(arity-test inexact? 1 1)

(err/rt-test (exact? 'a))
(err/rt-test (inexact? 'a))

(test "1.0" number->string 1.0)
(test "1.5e+100" number->string 1.5e+100)
(test "1.5e-100" number->string 1.5e-100)
(test "+inf.0" number->string +inf.0)
(test "-inf.0" number->string -inf.0)
(test "+nan.0" number->string +nan.0)
(test "+nan.0" number->string +nan.0)

(test "1589935744527.254" number->string 1589935744527.254)

#reader "maybe-single.rkt"
(begin
  (test (if has-single-flonum? "+inf.f" "+inf.0") number->string +inf.f)
  (test (if has-single-flonum? "-inf.f" "-inf.0") number->string -inf.f)
  (test (if has-single-flonum? "+nan.f" "+nan.0") number->string +nan.f)
  (test (if has-single-flonum? "+nan.f" "+nan.0") number->string +nan.f)
  (test (if has-single-flonum? "0.0f0" "0.0") number->string 0.0f0)
  (test (if has-single-flonum? "0.0f0" "0.0") number->string 0.0f1)
  (test (if has-single-flonum? "0.0f0" "0.0") number->string 0.0f17)
  (test (if has-single-flonum? "13.25f0" "13.25") number->string 13.25f0)
  (test (if has-single-flonum? "13.25f0" "13.25") number->string 1.325f1)
  (test (if has-single-flonum? "-4.25f0" "-4.25") number->string -4.25f0))

(map (lambda (n)
       ;; test that fresh strings are generated:
       (let ([n1 (number->string n)]
	     [n2 (number->string n)])
	 (string-set! n1 0 #\?)
	 (test n2 number->string n)
	 (test n1 string-append "?" (substring n2 1 (string-length n2)))))
     '(+inf.0 -inf.0 +nan.0 -nan.0 0.0 -0.0 0 1/2 3.4 1+2i))

(test #t = 0.0 -0.0)
(test #f eqv? 0.0 -0.0)
(test #f equal? 0.0 -0.0)
(test #f eqv? -0.0 0.0)
(test #t eqv? 0.0 0.0)
(test #t eqv? -0.0 -0.0)

(test #t = 22 22 22)
(test #t = 22 22)
(test #f = 34 34 35)
(test #f = 34 35)
(test #t > 3 -6246)
(test #f > 9 9 -2424)
(test #t >= 3 -4 -6246)
(test #t >= 9 9)
(test #f >= 8 9)
(test #t < -1 2 3 4 5 6 7 8)
(test #f < -1 2 3 4 4 5 6 7)
(test #t <= -1 2 3 4 5 6 7 8)
(test #t <= -1 2 3 4 4 5 6 7)
(test #f < 1 3 2)
(test #f >= 1 3 2)

(define (test-compare lo m hi) ; all positive!
  (define -lo (- lo))
  (define -m (- m))
  (define -hi (- hi))

  (define (test-lh l h)
    (test #f > l h)
    (test #t < l h)
    (test #f = l h)
    (test #f >= l h)
    (test #t <= l h))

  (define (test-hl h l)
    (test #t > h l)
    (test #f < h l)
    (test #f = h l)
    (test #t >= h l)
    (test #f <= h l))

  (define (test-zero z)
    (test-hl m z)
    (test-lh -m z)
    (test-hl z -m)
    (test-lh z m))

  (test-lh m hi)
  (test-hl -m -hi)

  (test #t > m)
  (test #t < m)
  (test #t = m)
  (test #t >= m)
  (test #t <= m)

  (test #f > m m)
  (test #f < m m)
  (test #t = m m)
  (test #t >= m m)
  (test #t <= m m)

  (test-hl m -m)
  (test-lh -m m)

  (test-hl m lo)
  (test-lh -m -lo)

  (test-zero 0)
  (test-zero 0.0))
  
(test-compare 0.5 1.2 2.3)
(test-compare 2/5 1/2 2/3)
(test-compare 1/4 1/3 1/2) ; same numerator
(test-compare 3/10 7/10 9/10) ; same denominator
(test-compare 2/500000000000000000000000000 1/200000000000000000000000000 2/300000000000000000000000000) ; bignums
(test #t = 1/2 2/4)
(test #f = 2/3 2/5)
(test #f = 2/3 2/500000000000000000000000000)

(test-compare 0.5 6/5 2.3)
(test-compare 1 11922615739/10210200 3000)
(test-compare 1.0 11922615739/10210200 3000.0)

(err/rt-test (< 1 2.3+0.0i))
(err/rt-test (> 1 2.3+0.0i))
(err/rt-test (<= 1 2.3+0.0i))
(err/rt-test (>= 1 2.3+0.0i))
(err/rt-test (< 2.3+0.0i 1))
(err/rt-test (> 2.3+0.0i 1))
(err/rt-test (<= 2.3+0.0i 1))
(err/rt-test (>= 2.3+0.0i 1))

(test #f > 0 (/ 1 (expt 2 400)))

(test #t < 0.5 2/3)
(test #f < 2/3 0.5)
(test #t = 0.5 1/2)
(test #t = +0.5i +1/2i)
(test #f = +0.5i 1+1/2i)
(test #t = 1 1.0+0i)
(test #t = 1 1.0+0.0i)
(test #f eqv? 1.0 1.0+0.0i)
(test #f eqv? 1.0-0.0i 1.0+0.0i)
(test #f eqv? 1.0+0.0i 1.0-0.0i)
(test #t eqv? 1.0+0.0i 1.0+0.0i)
(test #t eqv? 1.0-0.0i 1.0-0.0i)

(test #f = 1+2i 2+i)

;; Test transitivity in mixed exact--inexact settings
;; (Thanks again to Aubrey Jaffer for the starting point.)
(define (test-trans expect op nop a b c)
  ;; Make sure the tests check what we want to check:
  (test #t = (exact->inexact a) b)
  (test #t = (exact->inexact c) b)
  (test #t = (exact->inexact (- a)) (- b))
  (test #t = (exact->inexact (- c)) (- b))
  ;; The real tests:
  (test expect op a b)
  (test expect op b c)
  (test expect op a b c)
  (test expect nop (- a) (- b))
  (test expect nop (- b) (- c))
  (test expect nop (- a) (- b) (- c))
  (test expect nop c b)
  (test expect nop b a)
  (test expect nop c b a)
  (test expect op (- c) (- b))
  (test expect op (- b) (- a))
  (test expect op (- c) (- b) (- a)))
(test-trans #t < >= 1237940039285380274899124223 1.2379400392853803e+27 1237940039285380274899124225)
(test-trans #t < >= 3713820117856140824697372668/3 1.2379400392853803e+27 3713820117856140824697372676/3)
(test-trans #f > <= 1237940039285380274899124223 1.2379400392853803e+27 1237940039285380274899124225)
(test-trans #f > <= 3713820117856140824697372668/3 1.2379400392853803e+27 3713820117856140824697372676/3)
(test-trans #f = = 1237940039285380274899124223 1.2379400392853803e+27 1237940039285380274899124225)
(test-trans #f = = 3713820117856140824697372668/3 1.2379400392853803e+27 3713820117856140824697372676/3)
(test-trans #t <= > 1237940039285380274899124223 1.2379400392853803e+27 1237940039285380274899124225)
(test-trans #t <= > 3713820117856140824697372668/3 1.2379400392853803e+27 3713820117856140824697372676/3)
(test-trans #f >= < 1237940039285380274899124223 1.2379400392853803e+27 1237940039285380274899124225)
(test-trans #f >= < 3713820117856140824697372668/3 1.2379400392853803e+27 3713820117856140824697372676/3)

(define (test-nan.0 f . args)
  (apply test +nan.0 f args))

(define (test-i-nan.0 f . args)
  (apply test (make-rectangular +nan.0 +nan.0) f args))

;; these tests are also used as error tests, so provide a way to just call the operation
(define (test-nan c #:test? [test? #t])
  (define tst (if test? test (lambda (r c a b) (c a b))))
  (tst #f < +nan.0 c)
  (tst #f > +nan.0 c)
  (tst #f = +nan.0 c)
  (tst #f <= +nan.0 c)
  (tst #f >= +nan.0 c))
(test-nan 0)
(test-nan 0.0)
(test-nan 0.3)
(test-nan +nan.0)
(test-nan +inf.0)
(test-nan -inf.0)
(test-nan (expt 2 90))
(err/rt-test (test-nan 0.3+0.0i #:test? #f))
(test #f = +nan.0 1+2i)
(test #f = +nan.0 (make-rectangular +inf.0 -inf.0))

(test-compare 999999999999 1000000000000 1000000000001)
(define big-num (expt 2 1500))
(test-compare (sub1 big-num) big-num (add1 big-num))
(test-compare 1.0 (expt 10 100) 1e200)

(define (inf-zero-test inf rx negnot)
  (let ([inf-test-x
	 (lambda (r v)
	   (test r < v inf)
	   (test (not r) > v inf)
	   (test r <= v inf)
	   (test (not r) >= v inf)
	   
	   (test (not r) < inf v)
	   (test r > inf v)
	   (test (not r) <= inf v)
	   (test r >= inf v))])
    (inf-test-x rx 5)
    (inf-test-x (negnot rx) -5)
    (inf-test-x rx big-num)
    (inf-test-x (negnot rx) (- big-num))
    (inf-test-x rx (/ big-num 3))
    (inf-test-x (negnot rx) (/ (- big-num) 3))
    (inf-test-x rx (/ 1 big-num))
    (inf-test-x (negnot rx) (/ 1 (- big-num)))))
(inf-zero-test +inf.0 #t (lambda (x) x))
(inf-zero-test -inf.0 #f (lambda (x) x))
(inf-zero-test 0.0 #f not)

(err/rt-test (= 1 'a))
(err/rt-test (= 1 1 'a))
(err/rt-test (= 1 2 'a))
(err/rt-test (= 'a 1))
(err/rt-test (> 1 'a))
(err/rt-test (> 1 0 'a))
(err/rt-test (> 1 2 'a))
(err/rt-test (> 'a 1))
(err/rt-test (> 0.5+0.1i 1))
(err/rt-test (> 1 0.5+0.1i))
(err/rt-test (< 1 'a))
(err/rt-test (< 1 2 'a))
(err/rt-test (< 1 0 'a))
(err/rt-test (< 'a 1))
(err/rt-test (< 0.5+0.1i 1))
(err/rt-test (< 1 0.5+0.1i))
(err/rt-test (>= 1 'a))
(err/rt-test (>= 1 1 'a))
(err/rt-test (>= 1 2 'a))
(err/rt-test (>= 'a 1))
(err/rt-test (>= 0.5+0.1i 1))
(err/rt-test (>= 1 0.5+0.1i))
(err/rt-test (<= 1 'a))
(err/rt-test (<= 1 1 'a))
(err/rt-test (<= 1 0 'a))
(err/rt-test (<= 'a 1))
(err/rt-test (<= 0.5+0.1i 1))
(err/rt-test (<= 1 0.5+0.1i))

(arity-test = 1 -1)
(arity-test < 1 -1)
(arity-test > 1 -1)
(arity-test <= 1 -1)
(arity-test >= 1 -1)

(test #t zero? 0)
(test #t zero? 0.0)
(test #t zero? +0.0i)
(test #t zero? -0.0i)
(test #t zero? 0.0+0.0i)
(test #f zero? 1.0+0.0i)
(test #f zero? 1.0+1.0i)
(test #f zero? 0.0+1.0i)
(test #t zero? 0/1)
(test #f zero? 1)
(test #f zero? -1)
(test #f zero? -100)
(test #f zero? 1.0)
(test #f zero? -1.0)
(test #f zero? 1/2)
(test #f zero? -1/2)
(test #f zero? -1/2+2i)
(test #f zero? +inf.0)
(test #f zero? -inf.0)
(test #f zero? +nan.0)
(test #f zero? (expt 2 37))
(test #f zero? (expt -2 37))
(test #t positive? 4)
(test #f positive? -4)
(test #f positive? 0)
(test #t positive? 4.0)
(test #f positive? -4.0)
(test #f positive? 0.0)
(test #t positive? 2/4)
(test #f positive? -2/4)
(test #f positive? 0/2)
(test #t positive? +inf.0)
(test #f positive? -inf.0)
(test #f positive? +nan.0)
(test #t positive? (expt 2 37))
(test #f positive? (expt -2 37))
(test #f negative? 4)
(test #t negative? -4)
(test #f negative? 0)
(test #f negative? 4.0)
(test #t negative? -4.0)
(test #f negative? 0.0)
(test #f negative? 2/4)
(test #t negative? -2/4)
(test #f negative? 0/4)
(test #f negative? (expt 2 37))
(test #t negative? (expt -2 37))
(test #f negative? +inf.0)
(test #t negative? -inf.0)
(test #f negative? +nan.0)
(err/rt-test (negative? 5+0.0i))
(err/rt-test (negative? -5+0.0i))
(test #t odd? 3)
(test #f odd? 2)
(test #f odd? -4)
(test #t odd? -1)
(err/rt-test (odd? +inf.0))
(err/rt-test (odd? -inf.0))
(err/rt-test (odd? 5+0.0i))
(err/rt-test (odd? 4+0.0i))
(test #f odd? (expt 2 37))
(test #f odd? (expt -2 37))
(test #t odd? (add1 (expt 2 37)))
(test #t odd? (sub1 (expt -2 37)))
(test #f even? 3)
(test #t even? 2)
(test #t even? -4)
(test #f even? -1)
(err/rt-test (even? +inf.0))
(err/rt-test (even? -inf.0))
(err/rt-test (even? 4+0.0i))
(err/rt-test (even? 5+0.0i))
(test #t even? (expt 2 37))
(test #t even? (expt -2 37))
(test #f even? (add1 (expt 2 37)))
(test #f even? (sub1 (expt -2 37)))

(arity-test zero? 1 1)
(arity-test positive? 1 1)
(arity-test negative? 1 1)
(arity-test odd? 1 1)
(arity-test even? 1 1)

(err/rt-test (positive? 5+0.0i))
(err/rt-test (positive? -5+0.0i))
(err/rt-test (positive? 2+i))
(err/rt-test (negative? 2+i))
(err/rt-test (odd? 4.1))
(err/rt-test (odd? 4.1+0.0i))
(err/rt-test (odd? 4+1i))
(err/rt-test (even? 4.1))
(err/rt-test (even? 4.1+0.0i))
(err/rt-test (even? 4+1i))
(err/rt-test (even? +nan.0))

(err/rt-test (positive? 'i))
(err/rt-test (negative? 'i))
(err/rt-test (odd? 'a))
(err/rt-test (even? 'a))
(err/rt-test (odd? 'i))
(err/rt-test (even? 'i))

(test 5 max 5)
(test 5 min 5)
(test 38 max 34 5 7 38 6)
(test -24 min 3  5 5 330 4 -24)
(test 38.0 max 34 5.0 7 38 6)
(test -24.0 min 3  5 5 330 4 -24.0)
(test 2/3 max 1/2 2/3)
(test 2/3 max 2/3 1/2)
(test 2/3 max 2/3 -4/5)
(test 1/2 min 1/2 2/3)
(test 1/2 min 2/3 1/2)
(test -4/5 min 2/3 -4/5)
(test +inf.0 max +inf.0 0 -inf.0)
(test -inf.0 min +inf.0 0 -inf.0)
(test-nan.0 max +inf.0 +nan.0 0 -inf.0)
(test-nan.0 min +inf.0 0 +nan.0 -inf.0)
(err/rt-test (min 9.0+0.0i 100))
(err/rt-test (min 9.0+0.0i 8))
(err/rt-test (min 100 9.0+0.0i))
(err/rt-test (min 8 9.0+0.0i))
(err/rt-test (max 9.0+0.0i 100))
(err/rt-test (max 9.0+0.0i 8))
(err/rt-test (max 100 9.0+0.0i))
(err/rt-test (max 8 9.0+0.0i))

(test (expt 5 27) max 9 (expt 5 27))
(test (expt 5 29) max (expt 5 29) (expt 5 27))
(test (expt 5 29) max (expt 5 27) (expt 5 29))
(test (expt 5 27) max (expt 5 27) 9)
(test (expt 5 27) max (expt 5 27) (- (expt 5 29)))
(test (expt 5 27) max (- (expt 5 29)) (expt 5 27))
(test (- (expt 5 27)) max (- (expt 5 27)) (- (expt 5 29)))
(test (- (expt 5 27)) max (- (expt 5 29)) (- (expt 5 27)))
(test 9 min 9 (expt 5 27))
(test (expt 5 27) min (expt 5 29) (expt 5 27))
(test (expt 5 27) min (expt 5 27) (expt 5 29))
(test 9 min (expt 5 27) 9)
(test (- (expt 5 29)) min (expt 5 27) (- (expt 5 29)))
(test (- (expt 5 29)) min (- (expt 5 29)) (expt 5 27))
(test (- (expt 5 29)) min (- (expt 5 27)) (- (expt 5 29)))
(test (- (expt 5 29)) min (- (expt 5 29)) (- (expt 5 27)))
(test 0.0 expt -0.1 10000000000000.0)
(test -0.0 expt -0.1 10000000000001.0)
(test 0.0 expt -0.0 10000000000000.0)
(test -0.0 expt -0.0 10000000000001.0)
(test 0.0 expt -10.0 -10000000000000.0)
(test -0.0 expt -10.0 -10000000000001.0)

(test 0.0 expt 0.9999 (expt 2 5000))
(test 0.0 expt 0.9999 (add1 (expt 2 5000)))
(test 0.0 expt 0.9999 (/ (expt 2 5000) 3))
(test 0.0 expt -0.9999 (expt 2 5000))
(test -0.0 expt -0.9999 (add1 (expt 2 5000)))
(test 0.0f0 expt 0.9999f0 (expt 2 5000))
(test 0.0f0 expt 0.9999f0 (add1 (expt 2 5000)))
(test 0.0f0 expt 0.9999f0 (/ (expt 2 5000) 3))
(test 0.0f0 expt -0.9999f0 (expt 2 5000))
(test -0.0f0 expt -0.9999f0 (add1 (expt 2 5000)))

(test +inf.0 expt -4.0 (expt 2 5000))
(test -inf.0 expt -4.0 (add1 (expt 2 5000)))
(test +inf.f expt -4.0f0 (expt 2 5000))
(test -inf.f expt -4.0f0 (add1 (expt 2 5000)))
;; exponent large enough to overflow singles, but not doubles
#reader "maybe-single.rkt"
(when has-single-flonum?
  (test +inf.f expt -4.0f0 (lcm (exact-round -1.7976931348623151e+308)))
  (test -inf.f expt -4.0f0 (add1 (lcm (exact-round -1.7976931348623151e+308)))))

(test  5.540619075645279e+34 expt   1.000000000000001 (expt 2 56))
(test  5.540619075645279e+34 expt  -1.000000000000001 (expt 2 56))
(test -5.5406190756452855e+34 expt -1.000000000000001 (add1 (expt 2 56)))

(let ()
  (define nrs (list -inf.0 -2.0 -1.0 -0.5 -0.0 0.0 0.5 1.0 2.0 +inf.0))
  (define (neg-even nr) (- (- nr) 1))
  (define (neg-odd nr) (- nr))
  (define (pos-even nr) (+ nr 1))
  (define (pos-odd nr) nr)
  (for ([base (in-list nrs)])
    (for ([make-exponent (in-list (list neg-even neg-odd pos-even pos-odd))])
      (define L
        (for/list ([i (in-list '(14 150 350))])
          (expt base (make-exponent (string->number (build-string i (λ (i) #\1)))))))
      (test #t `(,base ,L) (apply = L)))))

(define (inf-non-real? x)
  (and (not (real? x))
       (= +inf.0 (abs (imag-part x)))
       (= +inf.0 (abs (real-part x)))))

(test #t inf-non-real? (expt -0.1 -1000000000000001/3)) ; inexact approx is non-integer
(test #t inf-non-real? (expt -0.1 -100000000000000000001/3)) ; inexact approx is integer


(err/rt-test (max 0 'a))
(err/rt-test (min 0 'a))
(err/rt-test (max 'a 0))
(err/rt-test (min 'a 0))
(err/rt-test (max 'a))
(err/rt-test (min 'a))
(err/rt-test (min 2 4+i))
(err/rt-test (max 2 4+i))
(err/rt-test (min 4+i))
(err/rt-test (max 4+i))

(arity-test max 1 -1)
(arity-test min 1 -1)

(test 0 +)
(test 7 + 3 4)
(test 6 + 1 2 3)
(test 7.0 + 3 4.0)
(test 6.0 + 1 2.0 3)
(test 19/12 + 1/4 1/3 1)
(test +i + +i)
(test 3/2+1i + 1 2+2i -i -3/2)
(test 3 + 3)
(test 0 +)
(test 4 * 4)
(test 16.0 * 4 4.0)
(test 1 *)
(test 6/25 * 3/5 1/5 2)
(test #i+6/25 * 3/5 1/5 2.0)
(test +6/25i * 3/5 1/5 2 +i)
(test (make-rectangular 0 #i+6/25) * 3/5 1/5 2.0 +i)
(test 18805208620685182736256260714897 
      * (sub1 (expt 2 31))  
      8756857658476587568751)
(test 1073741874 + (- (expt 2 30) 50) 100) ; fixnum -> bignum for 32 bits
(test -1073741874 - (- 50 (expt 2 30)) 100) ; fixnum -> bignum for 32 bits
(test 10.0+0.0i + 9.0+0.0i 1)
(test 10.0+0.0i + 9.0+0.0i 1-0.0i)
(test 9.0+0.0i * 9.0+0.0i 1)
(test 10.0-1.0i + 9.0+0.0i 1-1.0i)
(test 0 * 0 10.0)
(test 0 * 0 +inf.0)
(test 0 * 0 +nan.0)
(test 0 / 0 0.0)
(test 0 / 0 +inf.0)
(test 0 / 0 -inf.0)
(test 0 / 0 +nan.0)
(test -0.0 + 0 -0.0)
(test -0.0 + -0.0 0)
(test -0.0 - -0.0 0)

(test -0.0 - 0.0)
(test 0.0 - -0.0)
(test -0.0 - 0 0.0)
(test 0.0 - 0 -0.0)

(arity-test * 0 -1)
(arity-test + 0 -1)
(arity-test - 1 -1)
(arity-test / 1 -1)

(test 2 add1 1)
(test 0 add1 -1)
(test 2.0 add1 1.0)
(test 0.0 add1 -1.0)
(test 3/2 add1 1/2)
(test 1/2 add1 -1/2)
(test 2.0+i add1 1.0+i)
(test 0.0+i add1 -1.0+i)
(test 0.0+0.0i add1 -1+0.0i)
(test 0.0-0.0i add1 -1-0.0i)
(test 1073741824 add1 #x3FFFFFFF) ; fixnum boundary case

(err/rt-test (add1 "a"))
(arity-test add1 1 1)

(test 1 sub1 2)
(test -2 sub1 -1)
(test 1.0 sub1 2.0)
(test -2.0 sub1 -1.0)
(test -1/2 sub1 1/2)
(test -3/2 sub1 -1/2)
(test 1.0+i sub1 2.0+i)
(test -2.0+i sub1 -1.0+i)
(test -2.0+0.0i sub1 -1+0.0i)
(test -2.0-0.0i sub1 -1-0.0i)
(test -1073741824 sub1 -1073741823) ; fixnum boundary case

(err/rt-test (sub1 "a"))
(arity-test sub1 1 1)

(test 1024 expt 2 10)
(test 1/1024 expt 2 -10)
(test 1/1024 expt 1/2 10)
(test (/ 1 (expt 2 10000)) expt 1/2 10000)
(test 2 expt 4 1/2)
(test 2.0 expt 4 0.5)
(test (sqrt 5) expt 5 1/2)
(test 18446744073709551616 expt (expt 2 32) 2)
(arity-test expt 2 2)

(test 31525197391593472 inexact->exact 31525197391593473.0)
(test 31525197391593476 inexact->exact 31525197391593476.0)
(test 31525197391593476 inexact->exact 31525197391593476.0)

(test 0 apply + (map inexact->exact (list 3.2d+270 -2.4d+270 -8d+269)))
(test 0 apply + (map inexact->exact (list 3.2f+7 -2.4f+7 -8f+6)))

(test #t positive? (inexact->exact 0.1))
(test #t negative? (inexact->exact -0.1))
(test 0 + (inexact->exact -0.1) (inexact->exact 0.1))
(arity-test inexact->exact 1 1)
(err/rt-test (inexact->exact 'a))
(test 1+i inexact->exact 1.0+1.0i)
(test 1 inexact->exact 1.0+0.0i)
(test 1 inexact->exact 1.0-0.0i)

(test #t positive? (exact->inexact 1/10))
(test #t negative? (exact->inexact -1/10))
(test 0.0 + (exact->inexact -1/10) (exact->inexact 1/10))
(arity-test exact->inexact 1 1)
(err/rt-test (exact->inexact 'a))
(test 1.0+1.0i exact->inexact 1+1i)
(test 1.0+0.0i exact->inexact 1+0.0i)
(test (expt 7 30) inexact->exact (expt 7 30))

(err/rt-test (inexact->exact +inf.0))
(err/rt-test (inexact->exact -inf.0))
(err/rt-test (inexact->exact +nan.0))
#;(err/rt-test (begin (inexact->exact +inf.0) 'not-an-error))
#;(err/rt-test (begin (inexact->exact -inf.0) 'not-an-error))
#;(err/rt-test (begin (inexact->exact +nan.0) 'not-an-error))

#reader "maybe-single.rkt"
(when has-single-flonum?
  (err/rt-test (inexact->exact +inf.f) (lambda (exn) (regexp-match? #rx"[+]inf[.]f" (exn-message exn))))
  (err/rt-test (inexact->exact -inf.f) (lambda (exn) (regexp-match? #rx"[-]inf[.]f" (exn-message exn))))
  (err/rt-test (inexact->exact +nan.f) (lambda (exn) (regexp-match? #rx"[+]nan[.]f" (exn-message exn)))))

#reader "maybe-single.rkt"
(when has-single-flonum?
  (test 2.0f0 real->single-flonum 2)
  (test 2.25f0 real->single-flonum 2.25)
  (test 2.25f0 real->single-flonum 2.25f0)
  (test 2.0 real->double-flonum 2)
  (test 2.25 real->double-flonum 2.25)
  (test 2.25 real->double-flonum 2.25f0))

;; to make sure they work when jitted
(define (r->s-f x) (real->single-flonum x))
(define (r->d-f x) (real->double-flonum x))
#reader "maybe-single.rkt"
(when has-single-flonum?
  (test 2.0f0 r->s-f 2)
  (test 2.25f0 r->s-f 2.25)
  (test 2.25f0 r->s-f 2.25f0)
  (test 2.0 r->d-f 2)
  (test 2.25 r->d-f 2.25)
  (test 2.25 r->d-f 2.25f0))

(unless has-single-flonum?
  (err/rt-test (real->single-flonum 1.0) exn:fail:unsupported?)
  (err/rt-test (real->single-flonum +inf.0) exn:fail:unsupported?)
  (err/rt-test (real->single-flonum +nan.0) exn:fail:unsupported?))

(err/rt-test (* 'a 0))
(err/rt-test (+ 'a 0))
(err/rt-test (/ 'a 0))
(err/rt-test (- 'a 0))
(err/rt-test (+ 0 'a))
(err/rt-test (* 0 'a))
(err/rt-test (- 0 'a))
(err/rt-test (/ 0 'a))
(err/rt-test (+ 'a))
(err/rt-test (* 'a))
(err/rt-test (- 'a))
(err/rt-test (/ 'a))

(define (test-inf-plus-times v)
  (define (test+ +)
    (test +inf.0 + v (+ +inf.0))
    (test -inf.0 + v (+ -inf.0))
    (test +inf.0 + (- v) (+ +inf.0))
    (test -inf.0 + (- v) (+ -inf.0))
    
    (test +inf.0 + +inf.0 v)
    (test -inf.0 + -inf.0 v)
    (test +inf.0 + +inf.0 (- v))
    (test -inf.0 + -inf.0 (- v))

    (test-nan.0 + +nan.0 v)
    (test-nan.0 + v +nan.0))

  (test+ +)
  (test+ -)
  
  (test +inf.0 * +inf.0 v)
  (test -inf.0 * -inf.0 v)
  (test -inf.0 * +inf.0 (- v))
  (test +inf.0 * -inf.0 (- v))

  (test +inf.0 * v +inf.0)
  (test -inf.0 * v -inf.0)
  (test -inf.0 * (- v) +inf.0)
  (test +inf.0 * (- v) -inf.0)

  (test-nan.0 * +nan.0 v)
  (test-nan.0 * v +nan.0))

(test-inf-plus-times 1)
(test-inf-plus-times 1.0)
(test-inf-plus-times (expt 2 100))

(test -inf.0 - +inf.0)
(test +inf.0 - -inf.0)
(test +inf.0 + +inf.0 +inf.0)
(test -inf.0 + -inf.0 -inf.0)
(test-nan.0 + +inf.0 -inf.0)
(test-nan.0 - +inf.0 +inf.0)
(test-nan.0 - -inf.0 -inf.0)
(test +inf.0 * +inf.0 +inf.0)
(test -inf.0 * +inf.0 -inf.0)
(test 0 * +inf.0 0)
(test-nan.0 * +inf.0 0.0)
(test-nan.0 + +nan.0 +nan.0)
(test-nan.0 - +nan.0 +nan.0)
(test-nan.0 * +nan.0 +nan.0)

(test 1/2 / 1 2)
(test -1/3 / -1 3)
(test -1/3 / 1 -3)
(test 1/2 / 1/4 1/2)
(test 0.5 / 1 2.0)
(test 0.5 / 1.0 2)
(test 1/2+3/2i / 1+3i 2)
(test 1/5-3/5i / 2 1+3i)
(test 0.5+0.0i / 1+0.0i 2)
(test 0.25-0.0i / 1 4+0.0i)
(test 0.25+0.0i / 1+0.0i 4+0.0i)
(test 0 / 0 4+3i)
(test 0.25+0.0i / 1e300+1e300i (* 4 1e300+1e300i))
(test 0.25+0.0i / #e1e300+1e300i (* 4 1e300+1e300i))
(test 0.25+0.0i / 1e300+1e300i (* 4 #e1e300+1e300i))
(test 0.25+0.0i / 1e-300+1e-300i (* 4 1e-300+1e-300i))
(test 0.25+0.0i / #e1e-300+1e-300i (* 4 1e-300+1e-300i))
(test 0.25+0.0i / 1e-300+1e-300i (* 4 #e1e-300+1e-300i))
(test 1/2-1/2i / 1+1i)
(test 1/2+1/2i / 1-1i)
(test 1/5-2/5i / 1+2i)
(test 1/5+2/5i / 1-2i)
(test 2/5-1/5i / 2+1i)
(test 2/5+1/5i / 2-1i)
(test 0.5-0.5i / 1.0+1.0i)
(test 0.5+0.5i / 1.0-1.0i)
(test 0.2-0.4i / 1.0+2.0i)
(test 0.2+0.4i / 1.0-2.0i)
(test 0.4-0.2i / 2.0+1.0i)
(test 0.4+0.2i / 2.0-1.0i)
(test 0.0+0.0i / 0.0+0.0i 1+1e-320i)
(test 0.0+0.0i / 0.0+0.0i #e1+1e-320i)
(test -0.0+0.0i / -1.0e-9-1.0e+300i)
(test -0.0+0.0i / 1.0+0.0i -1.0e-9-1.0e+300i)
(test -0.0-0.0i / 0.0+1.0i -1.0e+300-1.0e-9i)
(test -0.0-0.0i / +1i -1.0e+300-1.0e-9i)
(test +nan.0+nan.0i / 0.0+0.0i)
(test 0.0-0.0i / 9.18e+55 4.0+1.79e+308i)
(test 0.0+nan.0i / 9.18e+55+0.0i 4.0+1.79e+308i)

(test 3 / 1 1/3)
(test -3 / 1 -1/3)
(test -3 / -1 1/3)
(test 3 / -1 -1/3)
(test 1/3 / 1 3)
(test -1/3 / 1 -3)
(test -1/3 / -1 3)
(test 1/3 / -1 -3)
(test 3/2 / 1 2/3)
(test -3/2 / 1 -2/3)
(test -3/2 / -1 2/3)
(test 3/2 / -1 -2/3)

(test (expt 3 50) / 1 (/ 1 (expt 3 50)))
(test (- (expt 3 50)) / 1 (- (/ 1 (expt 3 50))))
(test (- (expt 3 50)) / -1 (/ 1 (expt 3 50)))
(test (expt 3 50) / -1 (- (/ 1 (expt 3 50))))
(test (/ 1 (expt 3 50)) / 1 (expt 3 50))
(test (- (/ 1 (expt 3 50))) / 1 (- (expt 3 50)))
(test (- (/ 1 (expt 3 50))) / -1 (expt 3 50))
(test (/ 1 (expt 3 50)) / -1 (- (expt 3 50)))
(test (/ (expt 3 50) (expt 2 70)) / 1 (/ (expt 2 70) (expt 3 50)))
(test (- (/ (expt 3 50) (expt 2 70))) / 1 (- (/ (expt 2 70) (expt 3 50))))
(test (- (/ (expt 3 50) (expt 2 70))) / -1 (/ (expt 2 70) (expt 3 50)))
(test (/ (expt 3 50) (expt 2 70)) / -1 (/ (- (expt 2 70)) (expt 3 50)))

(test (- (expt 2 30)) / (- (expt 2 30)) 1)
(test (expt 2 30) / (- (expt 2 30)) -1)
(test (expt 2 29) / (- (expt 2 30)) -2)
(test -1/1073741824 / (- (expt 2 30)))

(test (expt 2 30) / (- (expt 2 30)) -1)

(test +inf.0 / 1.0 0.0)
(test -inf.0 / -1.0 0.0)
(test +inf.0 / -1.0 -0.0)
(test -inf.0 / 1.0 -0.0)

(define (make-test-inf-zero-div zero -zero inf -inf)
  (lambda (v)
    (test zero / v +inf.0)
    (test -zero / v -inf.0)
    (test -zero / (- v) +inf.0)
    (test zero / (- v) -inf.0)
    
    (test inf / +inf.0 v)
    (test -inf / -inf.0 v)
    (test -inf / +inf.0 (- v))
    (test inf / -inf.0 (- v))
    
    (unless (zero? v)
      (test zero / 0.0 v)
      (test -zero / 0.0 (- v))
      (test -zero / -0.0 v)
      (test zero / -0.0 (- v))
      
      (test inf / v 0.0)
      (test -inf / (- v) 0.0)
      (test -inf / v -0.0)
      (test inf / (- v) -0.0))
    
    (test-nan.0 / +nan.0 v)
    (test-nan.0 / v +nan.0)))

(define test-inf-zero-div (make-test-inf-zero-div 0.0 -0.0 +inf.0 -inf.0))
(define test-neg-inf-zero-div (make-test-inf-zero-div -0.0 0.0 -inf.0 +inf.0))

(test-inf-zero-div big-num)
(test-inf-zero-div (/ big-num 3))
(test-inf-zero-div 0.0)

(test-neg-inf-zero-div (- big-num))
(test-neg-inf-zero-div (- (/ big-num 3)))
(test-neg-inf-zero-div -0.0)

(test-nan.0 / +inf.0 +inf.0)
(test-nan.0 / +inf.0 -inf.0)
(test-nan.0 / +nan.0 -nan.0)

(test 1.0 exact->inexact (/ big-num (add1 big-num)))

(test 0.0 values (exact->inexact (/ (expt 2 5000) (add1 (expt 2 5000000)))))
(test -0.0 values (exact->inexact (/ (- (expt 2 5000)) (add1 (expt 2 5000000)))))
(test #t positive? (exact->inexact (* 5 (expt 10 -324))))
(test #t negative? (exact->inexact (* -5 (expt 10 -324))))
(test #t zero? (exact->inexact (* 5 (expt 10 -325))))
(test #t positive? (exact->inexact (* 45 (expt 10 -325))))

(err/rt-test (/ 0) exn:fail:contract:divide-by-zero?)
(err/rt-test (/ 1 0) exn:fail:contract:divide-by-zero?)
(err/rt-test (/ 1/2 0) exn:fail:contract:divide-by-zero?)
(err/rt-test (/ 1+2i 0) exn:fail:contract:divide-by-zero?)
(err/rt-test (/ 1.0 0) exn:fail:contract:divide-by-zero?)

(test -1 - 3 4)
(test -3 - 3)
(test -1.0 - 3.0 4)
(test -3.0 - 3.0)
(test 7 abs -7)
(test (expt 7 100) abs (- (expt 7 100)))
(test (expt 7 100) abs (expt 7 100))
(test 7.0 abs -7.0)
(test 7 abs 7)
(test 0 abs 0)
(test 1/2 abs 1/2)
(test 1/2 abs -1/2)
(test +inf.0 abs +inf.0)
(test +inf.0 abs -inf.0)
(test-nan.0 abs -nan.0)
(err/rt-test (abs -4.0+0.0i))

(test 1073741823 abs -1073741823)
(test 1073741823 abs 1073741823)
(test 1073741824 abs -1073741824)
(test 1073741824 abs 1073741824)
(test 1073741825 abs -1073741825)
(test 1073741825 abs 1073741825)

(arity-test abs 1 1)
(err/rt-test (-) exn:application:arity?)
(err/rt-test (abs 'a))
(err/rt-test (abs +5i))

(test 5 quotient 35 7)
(test 5.0 quotient 35 7.0)
(test 5.0 quotient 36 7.0)
(test 5.0 quotient 36.0 7)
(test -5 quotient -35 7)
(test -5.0 quotient -35 7.0)
(test -5 quotient 35 -7)
(test -5.0 quotient 35 -7.0)
(test 5 quotient -35 -7)
(test 5.0 quotient -35 -7.0)
(test -5.0 quotient -36 7.0)
(test -5.0 quotient 36.0 -7)
(err/rt-test (quotient 36.0 -7+0.0i))
(err/rt-test (quotient 36.0+0.0i -7))
(test 0 quotient 0 5.0)
(test 0 quotient 0 -5.0)
(test (expt 2 30) quotient (- (expt 2 30)) -1)
(test 1 modulo 13 4)
(test 1 remainder 13 4)
(test 1.0 modulo 13 4.0)
(test 1.0 remainder 13 4.0)
(test 3 modulo -13 4)
(test -1 remainder -13 4)
(test 3.0 modulo -13 4.0)
(test -1.0 remainder -13 4.0)
(test -3 modulo 13 -4)
(test 1 remainder 13 -4)
(test -3.0 modulo 13.0 -4)
(test 1.0 remainder 13.0 -4)
(test -1 modulo -13 -4)
(test -1 remainder -13 -4)
(test -1.0 modulo -13 -4.0)
(test -1.0 remainder -13 -4.0)
(err/rt-test (modulo -13 -4.0+0.0i))
(err/rt-test (remainder -13 -4.0+0.0i))
(err/rt-test (modulo -13+0.0i -4.0))
(err/rt-test (remainder -13+0.0i -4.0))
(test -2 remainder -3333333332 -3)
(test -2 modulo -3333333332 -3)
(test 2 remainder 3333333332 -3)
(test -1 modulo 3333333332 -3)
(test 0 modulo 4 2)
(test 0 modulo -4 2)
(test 0 modulo 4 -2)
(test 0 modulo -4 -2)
(test 0.0 modulo 4.0 2)
(test 0.0 modulo -4.0 2)
(test 0.0 modulo 4.0 -2)
(test 0.0 modulo -4.0 -2)
(test 1.0 modulo 21.0 2)
(test 1.0 modulo -21.0 2)
(test 0 remainder 4 2)
(test 0 remainder -4 2)
(test 0 remainder 4 -2)
(test 0 remainder -4 -2)
(test 0.0 remainder 4.0 2)
(test 0.0 remainder -4.0 2)
(test 0.0 remainder 4.0 -2)
(test 0.0 remainder -4.0 -2)
(test 1.0 remainder 21.0 2)
(test -1.0 remainder -21.0 2)
(test 0 modulo 0 5.0)
(test 0 modulo 0 -5.0)
(test 0 remainder 0 5.0)
(test 0 remainder 0 -5.0)
(test 0 modulo (- (expt 2 30)) -1)
(test 0 remainder (- (expt 2 30)) -1)
(define (divtest n1 n2)
	(= n1 (+ (* n2 (quotient n1 n2))
		 (remainder n1 n2))))
(test #t divtest 238 9)
(test #t divtest -238 9)
(test #t divtest 238 -9)
(test #t divtest -238 -9)

(test 13.0 quotient 1324.0 100)

(err/rt-test (quotient 6 0) exn:fail:contract:divide-by-zero?)
(err/rt-test (modulo 6 0) exn:fail:contract:divide-by-zero?)
(err/rt-test (remainder 6 0) exn:fail:contract:divide-by-zero?)
(err/rt-test (quotient 6 0.0) exn:fail:contract:divide-by-zero?)
(err/rt-test (modulo 6 0.0) exn:fail:contract:divide-by-zero?)
(err/rt-test (remainder 6 0.0) exn:fail:contract:divide-by-zero?)
(err/rt-test (quotient 6 -0.0) exn:fail:contract:divide-by-zero?)
(err/rt-test (modulo 6 -0.0) exn:fail:contract:divide-by-zero?)
(err/rt-test (remainder 6 -0.0) exn:fail:contract:divide-by-zero?)

(let ()
  (define (check-rem-mod a b rem mod)
    (test rem remainder a b)
    (test rem remainder (inexact->exact a) b)
    (test rem remainder a (inexact->exact b))
    (test mod modulo a b)
    (test mod modulo (inexact->exact a) b)
    (test mod modulo a (inexact->exact b)))
  (check-rem-mod 5.842423430828094e+60 10.0 4.0 4.0)
  (check-rem-mod 5.842423430828094e+60 -10.0 4.0 -6.0)
  (check-rem-mod -5.842423430828094e+60 10.0 -4.0 6.0)
  (check-rem-mod -5.842423430828094e+60 -10.0 -4.0 -4.0))

(define (test-qrm-inf v)
  (define iv (exact->inexact v))

  (err/rt-test (quotient v +inf.0))
  (err/rt-test (quotient v -inf.0))
  (err/rt-test (remainder v +inf.0))
  (err/rt-test (remainder v -inf.0))
  (err/rt-test (modulo v +inf.0))
  (err/rt-test (modulo v -inf.0))

  (err/rt-test (quotient +inf.0 v))
  (err/rt-test (quotient -inf.0 v))
  (err/rt-test (remainder +inf.0 v))
  (err/rt-test (remainder -inf.0 v))
  (err/rt-test (modulo +inf.0 v))
  (err/rt-test (modulo -inf.0 v)))

(test-qrm-inf 9)
(test-qrm-inf 9.0)
(test-qrm-inf (expt 2 100))
(test-qrm-inf 0.0)
(test-qrm-inf -0.0)

;; Check 0.0 combinations
(test -0.0 quotient -0.0 2.0)
(test 0.0 quotient -0.0 -2.0)
(test 0.0 quotient 0.0 2.0)
(test -0.0 quotient 0.0 -2.0)
(test 0.0 modulo -0.0 2.0)
(test 0.0 modulo -0.0 -2.0)
(test 0.0 modulo 0.0 2.0)
(test 0.0 modulo 0.0 -2.0)
(test 0.0 remainder -0.0 2.0)
(test 0.0 remainder -0.0 -2.0)
(test 0.0 remainder 0.0 2.0)
(test 0.0 remainder 0.0 -2.0)

(arity-test quotient 2 2)
(arity-test modulo 2 2)
(arity-test remainder 2 2)

(err/rt-test (quotient 'a 1))
(err/rt-test (quotient 1 'a))
(err/rt-test (quotient 1 +nan.0))
(err/rt-test (quotient +nan.0 1))
(err/rt-test (modulo 'a 1))
(err/rt-test (modulo 1 'a))
(err/rt-test (modulo +nan.0 1))
(err/rt-test (modulo 1 +nan.0))
(err/rt-test (remainder 'a 1))
(err/rt-test (remainder 1 'a))
(err/rt-test (remainder +nan.0 1))
(err/rt-test (remainder 1 +nan.0))
(err/rt-test (quotient 'a 1.0))
(err/rt-test (quotient 1.0 'a))
(err/rt-test (modulo 'a 1.0))
(err/rt-test (modulo 1.0 'a))
(err/rt-test (remainder 'a 1.0))
(err/rt-test (remainder 1.0 'a))
(err/rt-test (quotient 1/2 1))
(err/rt-test (remainder 1/2 1))
(err/rt-test (modulo 1/2 1))
(err/rt-test (quotient 2 1/2))
(err/rt-test (remainder 2 1/2))
(err/rt-test (modulo 2 1/2))
(err/rt-test (quotient 12.3 1))
(err/rt-test (remainder 12.3 1))
(err/rt-test (modulo 12.3 1))
(err/rt-test (quotient 2 12.3))
(err/rt-test (remainder 2 12.3))
(err/rt-test (modulo 2 12.3))
(err/rt-test (quotient 1+2i 1))
(err/rt-test (remainder 1+2i 1))
(err/rt-test (modulo 1+2i 1))
(err/rt-test (quotient 2 1+2i))
(err/rt-test (remainder 2 1+2i))
(err/rt-test (modulo 2 1+2i))

(test (- (expt 2 65) (expt 2 62))
      modulo (- (+ (expt 2 62) (expt 2 65))) (expt 2 65))
(test (- (expt 2 33) (expt 2 30))
      modulo (- (+ (expt 2 30) (expt 2 33))) (expt 2 33))
(test (- (expt 2 62))
      remainder (- (+ (expt 2 62) (expt 2 65))) (expt 2 65))
(test (- (expt 2 30))
      remainder (- (+ (expt 2 30) (expt 2 33))) (expt 2 33))

(test 10 bitwise-ior 10)
(test 10 bitwise-and 10)
(test 10 bitwise-xor 10)
(test 7 bitwise-ior 3 4)
(test 0 bitwise-and 3 4)
(test 7 bitwise-xor 3 4)
(test 7 bitwise-ior 3 4 1)
(test 1 bitwise-and 3 5 1)
(test 6 bitwise-xor 3 4 1)

(test #x1ffff7777 bitwise-ior #x1aaaa5555 #x155553333)
(test #x100001111 bitwise-and #x1aaaa5555 #x155553333)
(test #x0ffff6666 bitwise-xor #x1aaaa5555 #x155553333)

(test #x3ffff7777 bitwise-ior #x2aaaa5555 #x155553333)
(test #x000001111 bitwise-and #x2aaaa5555 #x155553333)
(test #x3ffff6666 bitwise-xor #x2aaaa5555 #x155553333)

(test #x3ffff7777 bitwise-ior #x2aaaa5555 #x155553333)
(test #x000001111 bitwise-and #x2aaaa5555 #x155553333)
(test #x3ffff6666 bitwise-xor #x2aaaa5555 #x155553333)

(test #xfffffffffffffe bitwise-not #x-FFFFFFFFFFFFFF)
(test #x-100000000000000 bitwise-not #xFFFFFFFFFFFFFF)

(test (bitwise-and (bitwise-not #x-2aaaa5555) (bitwise-not #x-15555aaaa))
      bitwise-not (bitwise-ior #x-2aaaa5555 #x-15555aaaa))
(test (bitwise-and (bitwise-not #x-2aaaa5555) (bitwise-not #x-155553333))
      bitwise-not (bitwise-ior #x-2aaaa5555 #x-155553333))
(test (bitwise-and (bitwise-not #x-2aaaa5555) (bitwise-not #x-15555333))
      bitwise-not (bitwise-ior #x-2aaaa5555 #x-15555333))

(test #x-155553333 bitwise-xor #x-2aaaa5555 (bitwise-xor #x-2aaaa5555 #x-155553333))
(test #x-15555333 bitwise-xor #x-2aaaa5555 (bitwise-xor #x-2aaaa5555 #x-15555333))

(test -1 bitwise-and)
(test 0 bitwise-ior)
(test 0 bitwise-xor)

(arity-test bitwise-ior 0 -1)
(arity-test bitwise-and 0 -1)
(arity-test bitwise-xor 0 -1)
(arity-test bitwise-not 1 1)

(define error-test-bitwise-procs
  (lambda (v)
    (err/rt-test (bitwise-ior v))
    (err/rt-test (bitwise-and v))
    (err/rt-test (bitwise-xor v))
    (err/rt-test (bitwise-not v))
    (err/rt-test (bitwise-ior 1 v))
    (err/rt-test (bitwise-and 1 v))
    (err/rt-test (bitwise-xor 1 v))
    (err/rt-test (bitwise-ior v 1))
    (err/rt-test (bitwise-and v 1))
    (err/rt-test (bitwise-xor v 1))))

(error-test-bitwise-procs 1.0)
(error-test-bitwise-procs 1/2)
(error-test-bitwise-procs 1+2i)
(error-test-bitwise-procs 1.0+0.0i)
(error-test-bitwise-procs +inf.0)
(error-test-bitwise-procs ''a)

(test 1 arithmetic-shift 1 0)
(test 1024 arithmetic-shift 1 10)
(test 1 arithmetic-shift 1024 -10)
(test 256 arithmetic-shift 1024 -2)
(test 0 arithmetic-shift 1024 -11)
(test 0 arithmetic-shift 1024 -20)
(test 0 arithmetic-shift 1024 -40)
(test 0 arithmetic-shift 1024 -20000000000000000000)
(test 0 arithmetic-shift 0 100)
(test 0 arithmetic-shift 0 -100)
(test 0 arithmetic-shift 17 -32)

(test (expt 2 40) arithmetic-shift (expt 2 40) 0)
(test (expt 2 50) arithmetic-shift (expt 2 40) 10)
(test (expt 2 30) arithmetic-shift (expt 2 40) -10) ; somewhere close to here is a boundary...
(test (expt 2 29) arithmetic-shift (expt 2 40) -11)
(test (expt 2 31) arithmetic-shift (expt 2 40) -9)
(test 1 arithmetic-shift (expt 2 40) -40)
(test 0 arithmetic-shift (expt 2 40) -41)
(test 0 arithmetic-shift (expt 2 40) -100)

(test -1 arithmetic-shift -1 0)
(test -1024 arithmetic-shift -1 10)
(test -1 arithmetic-shift -1024 -10)
(test -256 arithmetic-shift -1024 -2)
(test -1 arithmetic-shift -1024 -11)
(test -1 arithmetic-shift -1024 -20)
(test -1 arithmetic-shift -1024 -20000000000000000000)

(test (- (expt 2 40)) arithmetic-shift (- (expt 2 40)) 0)
(test (- (expt 2 50)) arithmetic-shift (- (expt 2 40)) 10)
(test (- (expt 2 30)) arithmetic-shift (- (expt 2 40)) -10) ; somewhere close to here is a boundary...
(test (- (expt 2 29)) arithmetic-shift (- (expt 2 40)) -11)
(test (- (expt 2 31)) arithmetic-shift (- (expt 2 40)) -9)
(test -1 arithmetic-shift (- (expt 2 40)) -40)
(test -1 arithmetic-shift (- (expt 2 40)) -41)
(test -1 arithmetic-shift (- (expt 2 40)) -100)

(test 0 arithmetic-shift (sub1 (expt 2 30)) -32)
(test 0 arithmetic-shift (sub1 (expt 2 31)) -32)
(test 0 arithmetic-shift (sub1 (expt 2 32)) -32)
(test 1 arithmetic-shift (expt 2 32) -32)

(for ([i (in-range -2 3)])
  (test 0 arithmetic-shift 42 (+ i (- (expt 2 31))))
  (test 0 arithmetic-shift 42 (+ i (- (expt 2 63)))))

(test 0 arithmetic-shift 0 (expt 2 100))
(test 0 arithmetic-shift 0 (- (expt 2 100)))
(test 0 arithmetic-shift 1 (- (expt 2 100)))
(test 0 arithmetic-shift (expt 2 100) (- (expt 2 100)))
(test -1 arithmetic-shift -1 (- (expt 2 100)))
(test -1 arithmetic-shift (- (expt 2 100)) (- (expt 2 100)))

(arity-test arithmetic-shift 2 2)
(err/rt-test (arithmetic-shift "a" 1))
(err/rt-test (arithmetic-shift 1 "a"))
(err/rt-test (arithmetic-shift 1.0 1))
(err/rt-test (arithmetic-shift 1 1.0))
(err/rt-test (arithmetic-shift 1 1.0+0.0i))
(err/rt-test (eval '(arithmetic-shift 1 (expt 2 80))) exn:fail:out-of-memory?)

(test #f bitwise-bit-set? 13 1)
(test #t bitwise-bit-set? 13 2)
(test #f bitwise-bit-set? 13 (expt 2 101))
(test #t bitwise-bit-set? -13 (expt 2 101))
(test #f bitwise-bit-set? (+ (expt 2 101) 13) 1)
(test #t bitwise-bit-set? (+ (expt 2 101) 13) 2)
(test #f bitwise-bit-set? (arithmetic-shift 13 101) (+ 101 1))
(test #t bitwise-bit-set? (arithmetic-shift 13 101) (+ 101 2))
(test #f bitwise-bit-set? (- (expt 2 101)) 0)
(test #f bitwise-bit-set? (- (expt 2 101)) 1)
(test #t bitwise-bit-set? (- (sub1 (expt 2 101))) 0)
(test #t bitwise-bit-set? (bitwise-not (expt 2 101)) 70)

(arity-test bitwise-bit-set? 2 2)
(err/rt-test (bitwise-bit-set? "a" 1))
(err/rt-test (bitwise-bit-set? 13 "a"))
(err/rt-test (bitwise-bit-set? 13 -1))
(err/rt-test (bitwise-bit-set? 13 (- (expt 2 101))))

(test 0 bitwise-bit-field 13 0 0)
(test 1 bitwise-bit-field 13 0 1)
(test 0 bitwise-bit-field 13 1 1)
(test 0 bitwise-bit-field 13 1 2)
(test 2 bitwise-bit-field 13 1 3)
(test 0 bitwise-bit-field 13 3 3)
(test 6 bitwise-bit-field 13 1 4)
(test 6 bitwise-bit-field 13 1 10)
(test 6 bitwise-bit-field 13 1 100)
(test 3 bitwise-bit-field 13 2 10)
(test 3 bitwise-bit-field 13 2 100)
(test 0 bitwise-bit-field (arithmetic-shift 13 101) 0 0)
(test 6 bitwise-bit-field (arithmetic-shift 13 101) (+ 1 101) (+ 4 101))
(test #t 'all-six
      ;; checks boundaries of bignums
      (for/and ([i (in-range 101 171)])
        (and (= 6 (bitwise-bit-field (arithmetic-shift 13 i) (+ 1 i) (+ 4 i)))
             (= 6 (bitwise-bit-field (arithmetic-shift 13 i) (+ 1 i) 400)))))
(test 1 bitwise-bit-field -13 0 1)
(test 0 bitwise-bit-field -14 0 1)
(test 1 bitwise-bit-field -13 1 2)
(test 1 bitwise-bit-field -13 28 29)
(test #b111111111111 bitwise-bit-field -13 28 40)
(test #b111111111111 bitwise-bit-field -13 1028 1040)
(test 0 bitwise-bit-field (- (expt 2 101)) 0 0)
(test 1 bitwise-bit-field (- (sub1 (expt 2 101))) 0 1)
(test 1 bitwise-bit-field (bitwise-not (expt 2 101)) 70 71)
(test 7144187 bitwise-bit-field (expt 3 75) 0 24)

;; More boundary checking, especially for returning a
;; value that goes negative if mistreated as a fixnum:
(let ()
  (define (bitwise-bit-field* n start end)
    (bitwise-and (sub1 (arithmetic-shift 1 (- end start)))
                 (arithmetic-shift n (- start))))

  (define (check-bit-field n)
    (for ([i (in-range 200)])
      (define lo 0)
      (define hi i)
      (test (bitwise-bit-field* n lo hi)
            bitwise-bit-field n lo hi))
    (for ([j (in-range 0 100)])
      (for ([i (in-range j 200)])
        (define lo (- i j))
        (define hi i)
        (test (bitwise-bit-field* n lo hi)
              bitwise-bit-field n lo hi))))

  (check-bit-field -1)
  (check-bit-field (sub1 (expt 2 30)))
  (check-bit-field (sub1 (expt 2 62)))
  (check-bit-field (sub1 (arithmetic-shift 1 300))))

(test 42 bitwise-bit-field 42 0 32)
(test (sub1 (expt 2 32)) bitwise-bit-field -1 32 64)

(arity-test bitwise-bit-field 3 3)
(err/rt-test (bitwise-bit-field "a" 1 2))
(err/rt-test (bitwise-bit-field 13 -1 2))
(err/rt-test (bitwise-bit-field 13 0 -1))
(err/rt-test (bitwise-bit-field 13 2 1))
(err/rt-test (bitwise-bit-field 13 (expt 2 101) (sub1 (expt 2 101))))

(test 4 gcd 0 4)
(test 4 gcd -4 0)
(test 4 gcd 4)
(test 4 gcd -4)
(test 4 gcd 32 -36)
(test 2 gcd 6 10 14)
(test 0 gcd)
(test 5 gcd 5)
(test 5.0 gcd 5.0 10)
(test 5.0 gcd -5.0 10)
(test 5.0 gcd 5.0 -10)
(test 5.0 gcd 5.0)
(test 5.0 gcd -5.0)
(test 3 gcd 0 0 3 0)
(test 3.0 gcd 0.0 0 3 0)
(test 0 gcd 0 0 0)
(err/rt-test (gcd 5.0+0.0i 10))
(err/rt-test (gcd 5.0 10+0.0i))
(test (expt 3 37) gcd (expt 9 35) (expt 6 37))
(test (expt 3 37) gcd (- (expt 9 35)) (expt 6 37))
(test (expt 3 37) gcd (expt 9 35) (- (expt 6 37)))
(test (expt 3 75) gcd (expt 3 75))
(test (expt 3 75) gcd (- (expt 3 75)))
(test 201 gcd (* 67 (expt 3 20)) (* 67 3))
(test 201 gcd (* 67 3) (* 67 (expt 3 20)))
(test 6 gcd (* 3 (expt 2 100)) 66)
(test 6 gcd 66 (* 3 (expt 2 100)))
(test 201.0 gcd (* 67 (expt 3 20)) (* 67. 3))
(test 201.0 gcd (* 67. 3) (* 67 (expt 3 20)))
(test (expt 9 35) gcd (expt 9 35) 0)
(test (expt 9 35) gcd 0 (expt 9 35))
(test 288 lcm 32 -36)
(test 12 lcm 2 3 4)
(test 1 lcm)
(test 5 lcm 5)
(test 5 lcm -5)
(test 0 lcm 123 0)
(test 0 lcm 0 0)
(test 0.0 lcm 0 0.0)
(test 0.0 lcm 0.0 0)
(test 30.0 lcm 5 6.0)
(test 6.0 lcm 6.0)
(test 6.0 lcm -6.0)
(err/rt-test (lcm 5 6.0+0.0i))
(err/rt-test (lcm 5+0.0i 6.0))
(test 0.0 lcm 123 0.0)
(test 0.0 lcm 123 -0.0)
(test (* (expt 2 37) (expt 9 35)) lcm (expt 9 35) (expt 6 37))
(test (* (expt 2 37) (expt 9 35)) lcm (- (expt 9 35)) (expt 6 37))
(test (* (expt 2 37) (expt 9 35)) lcm (expt 9 35) (- (expt 6 37)))

(test 1/2 gcd 1/2)
(test 1/2 gcd 3 1/2)
(test 1/2 gcd 1/2 3)
(test 1/105 gcd 1/3 2/5 3/7)
(test 0.5 gcd 0.5 3)
(test 0.5 gcd 1/2 3.0)
(test 1/2 lcm 1/2)
(test 3 lcm 3 1/2)
(test 3 lcm 1/2 3)
(test 2/3 lcm 1/3 2/3)
(test 6 lcm 1/3 2/5 3/7)
(test 3.0 lcm 0.5 3)
(test 3.0 lcm 1/2 3.0)

(test 4611686018427387904 gcd -4611686018427387904)
(test 4611686018427387904 gcd -4611686018427387904 -4611686018427387904)
(test 4611686018427387904 gcd -4611686018427387904 0)

(err/rt-test (gcd +nan.0))
(err/rt-test (gcd +inf.0))
(err/rt-test (gcd -inf.0))
(err/rt-test (gcd 'a))
(err/rt-test (gcd 'a 1))
(err/rt-test (gcd 1 'a))
(err/rt-test (lcm +nan.0))
(err/rt-test (lcm +inf.0))
(err/rt-test (lcm -inf.0))
(err/rt-test (lcm 'a))
(err/rt-test (lcm 'a 1))
(err/rt-test (lcm 1 'a))
(err/rt-test (gcd 1+2i))
(err/rt-test (lcm 1+2i))
(err/rt-test (gcd 1 1+2i))
(err/rt-test (lcm 1 1+2i))
(err/rt-test (gcd +nan.0 5.0))
(err/rt-test (gcd 5.0 +nan.0))
(err/rt-test (lcm +nan.0 5.0))
(err/rt-test (lcm 5.0 +nan.0))
(err/rt-test (gcd +inf.0 5.0))
(err/rt-test (gcd 5.0 +inf.0))
(err/rt-test (lcm +inf.0 5.0))
(err/rt-test (lcm 5.0 +inf.0))

(arity-test gcd 0 -1)
(arity-test lcm 0 -1)

(test 2 floor 5/2)
(test 3 ceiling 5/2)
(test 2 round 5/2)
(test 2 truncate 5/2)
(test -3 floor -5/2)
(test -2 ceiling -5/2)
(test -2 round -5/2)
(test -2 truncate -5/2)

(test 1 floor 4/3)
(test 2 ceiling 4/3)
(test 1 round 4/3)
(test 1 truncate 4/3)
(test -2 floor -4/3)
(test -1 ceiling -4/3)
(test -1 round -4/3)
(test -1 truncate -4/3)

(test 1 floor 5/3)
(test 2 ceiling 5/3)
(test 2 round 5/3)
(test 1 truncate 5/3)
(test -2 floor -5/3)
(test -1 ceiling -5/3)
(test -2 round -5/3)
(test -1 truncate -5/3)

(test 2 floor 11/4)
(test 3 ceiling 11/4)
(test 3 round 11/4)
(test 2 truncate 11/4)
(test -3 floor -11/4)
(test -2 ceiling -11/4)
(test -3 round -11/4)
(test -2 truncate -11/4)

(test 2 floor 9/4)
(test 3 ceiling 9/4)
(test 2 round 9/4)
(test 2 truncate 9/4)
(test -3 floor -9/4)
(test -2 ceiling -9/4)
(test -2 round -9/4)
(test -2 truncate -9/4)

(test 2.0 floor 2.4)
(test 3.0 ceiling 2.4)
(test 2.0 round 2.4)
(test 2.0 truncate 2.4)
(test -3.0 floor -2.4)
(test -2.0 ceiling -2.4)
(test -2.0 round -2.4)
(test -2.0 truncate -2.4)

(test 2.0 floor 2.6)
(test 3.0 ceiling 2.6)
(test 3.0 round 2.6)
(test 2.0 truncate 2.6)
(test -3.0 floor -2.6)
(test -2.0 ceiling -2.6)
(test -3.0 round -2.6)
(test -2.0 truncate -2.6)

(test 2.0 round 2.5)
(test -2.0 round -2.5)
(test 4.0 round 3.5)
(test -4.0 round -3.5)
(test -0.0 round -0.5)

(define (test-zero-ident f)
  (test 0.0 f 0.0)
  (test -0.0 f -0.0))
(test-zero-ident round)
(test-zero-ident floor)
(test-zero-ident ceiling)
(test-zero-ident truncate)

(err/rt-test (floor 2.6+0.0i))
(err/rt-test (ceiling 2.6+0.0i))
(err/rt-test (round 2.6+0.0i))
(err/rt-test (truncate 2.6+0.0i))
(test +inf.0 floor +inf.0)
(test +inf.0 ceiling +inf.0)
(test +inf.0 round +inf.0)
(test +inf.0 truncate +inf.0)
(test -inf.0 floor -inf.0)
(test -inf.0 ceiling -inf.0)
(test -inf.0 round -inf.0)
(test -inf.0 truncate -inf.0)
(test +nan.0 floor +nan.0)
(test +nan.0 ceiling +nan.0)
(test +nan.0 round +nan.0)
(test +nan.0 truncate +nan.0)

(define (test-fcrt-int v)
  (test v floor v)
  (test v ceiling v)
  (test v round v)
  (test v truncate v))

(test-fcrt-int 2)
(test-fcrt-int 2.0)
(test-fcrt-int (expt 2 100))

(arity-test round 1 1)
(arity-test floor 1 1)
(arity-test ceiling 1 1)
(arity-test truncate 1 1)

(err/rt-test (floor 2+i))
(err/rt-test (ceiling 2+i))
(err/rt-test (truncate 2+i))
(err/rt-test (round 2+i))

(err/rt-test (floor "a"))
(err/rt-test (ceiling "a"))
(err/rt-test (truncate "a"))
(err/rt-test (round "a"))

(test 5 numerator 5)
(test 5000000000000 numerator 5000000000000)
(test 5.0 numerator 5.0)
(err/rt-test (numerator 5.0+0.0i))
(test 1 denominator 5)
(test 1 denominator 5000000000000)
(test 1.0 denominator 5.0)
(err/rt-test (denominator 5.0+0.0i))
(test 2 numerator 2/3)
(test 3 denominator 2/3)
(test 1000.0 round (* 10000.0 (/ (numerator 0.1) (denominator 0.1))))

(err/rt-test (numerator +inf.0))
(err/rt-test (numerator -inf.0))
(err/rt-test (numerator +nan.0))
(err/rt-test (denominator +inf.0))
(err/rt-test (denominator -inf.0))
(err/rt-test (denominator +nan.0))

(err/rt-test (numerator 'a))
(err/rt-test (numerator 1+2i))
(err/rt-test (denominator 'a))
(err/rt-test (denominator 1+2i))

(arity-test numerator 1 1)
(arity-test denominator 1 1)

(define (test-on-reals f filter)
  (test (filter 5) f 5)
  (test (filter 5.0) f 5.0)
  (test (filter 1/5) f 1/5)
  (test (filter (expt 2 100)) f (expt 2 100)))

(test 1+2i make-rectangular 1 2)
(test 1.0+2.0i make-rectangular 1.0 2)
(err/rt-test (make-rectangular 1.0+0.0i 2))
(err/rt-test (make-rectangular 1.0 2+0.0i))
(test-nan.0 real-part (make-rectangular +nan.0 1))
(test 1.0 imag-part (make-rectangular +nan.0 1))
(test-nan.0 imag-part (make-rectangular 1 +nan.0))
(test 1.0 real-part (make-rectangular 1 +nan.0))
(test +inf.0 real-part (make-rectangular +inf.0 -inf.0))
(test -inf.0 imag-part (make-rectangular +inf.0 -inf.0))

(test (make-rectangular +inf.0 -inf.0) * 1. (make-rectangular +inf.0 -inf.0))
(when has-exact-zero-inexact-complex?
  (test (make-rectangular +inf.0 +inf.0) * +1.0i (make-rectangular +inf.0 -inf.0)))
(test (make-rectangular -inf.0 +inf.0) * -3. (make-rectangular +inf.0 -inf.0))
(test (make-rectangular +inf.0 -inf.0) * (make-rectangular +inf.0 -inf.0) 1.)
(when has-exact-zero-inexact-complex?
  (test (make-rectangular +inf.0 +inf.0) * (make-rectangular +inf.0 -inf.0) +1.0i))
(test (make-rectangular -inf.0 +inf.0) * (make-rectangular +inf.0 -inf.0) -3.)
(test (make-rectangular +inf.0 -inf.0) / (make-rectangular +inf.0 -inf.0) 1.)
(when has-exact-zero-inexact-complex?
  (test (make-rectangular -inf.0 -inf.0) / (make-rectangular +inf.0 -inf.0) +1.0i))
(test (make-rectangular -inf.0 +inf.0) / (make-rectangular +inf.0 -inf.0) -3.)

;; Test division with exact zeros in demoniator where
;;  the exact zero gets polluted to an inexact zero unless
;;  it's special-cased
(when has-exact-zero-inexact-complex?
  (test 0-0.0i / 0+1.0i -inf.0))
(test -0.0-0.0i / 1.0+1.0i -inf.0)
(when has-exact-zero-inexact-complex?
  (test -0.0 / 0+1.0i 0-inf.0i)
  (test -0.0+0.0i / 1.0+1.0i 0-inf.0i))

(test-i-nan.0 * 1.+0.i (make-rectangular +inf.0 -inf.0))
(test-i-nan.0 * 0.+1.0i (make-rectangular +inf.0 -inf.0))
(test-i-nan.0 * -3.+0.i (make-rectangular +inf.0 -inf.0))
(test-i-nan.0 * (make-rectangular +inf.0 -inf.0) 1.+0.i)
(test-i-nan.0 * (make-rectangular +inf.0 -inf.0) 0.+1.0i)
(test-i-nan.0 * (make-rectangular +inf.0 -inf.0) -3.+0.i)
(test-i-nan.0 / (make-rectangular +inf.0 -inf.0) 1.+0.i)
(test-i-nan.0 / (make-rectangular +inf.0 -inf.0) 0.+1.0i)
(test-i-nan.0 / (make-rectangular +inf.0 -inf.0) -3.+0.i)

(test 1 magnitude 1)
(test 1 magnitude -1)
(test 1.0 magnitude 1.0)
(test 1.0 magnitude -1.0)
(test big-num magnitude big-num)
(test big-num magnitude (- big-num))
(test 3/4 magnitude 3/4)
(test 3/4 magnitude -3/4)
(test 10.0 magnitude 10.0+0.0i)
(test 10.0 magnitude -10.0+0.0i)
(test 10.0 magnitude 0+10.0i)
(test 10 magnitude 0+10i)
(test 141421.0 round (* 1e-295 (magnitude 1e300+1e300i)))
(test 141421.0 round (* 1e+305 (magnitude 1e-300+1e-300i)))
(test +inf.0 magnitude +inf.0+inf.0i)
(test +inf.0 magnitude -inf.0-inf.0i)
(test +inf.0 magnitude 1+inf.0i)
(test +inf.0 magnitude +inf.0+1i)
(test +inf.0 magnitude +inf.0+0.0i)
(test +inf.0 magnitude 0.0+inf.0i)
(test +inf.0 magnitude +nan.0+inf.0i)
(test +inf.0 magnitude +inf.0+nan.0i)
(test +nan.0 magnitude +nan.0+2.0i)
(test +nan.0 magnitude +2.0+nan.0i)
(test +nan.0 magnitude 0+nan.0i)
(test +inf.f magnitude 3.0f0-inf.fi)
(test +nan.f magnitude 3.0f0+nan.fi)
(test 3.0f0 magnitude 3.0f0+0.0f0i)

(test 0 angle 1)
(test 0 angle 1.0)
(test 0 angle 0.0)
(test 0 angle big-num)
(test 0 angle 3/4)
(test 0.0 angle 3+0.0i)
(test-nan.0 angle +nan.0)
(let ([pi (atan 0 -1)])
  (test pi angle -1)
  (test pi angle -1.0)
  (test pi angle -0.0)
  (test pi angle (- big-num))
  (test pi angle -3/4)
  (test pi angle -3+0.0i))

(err/rt-test (angle 'a))
(err/rt-test (angle 0) exn:fail:contract:divide-by-zero?)
(err/rt-test (magnitude 'a))
(arity-test angle 1 1)
(arity-test magnitude 1 1)

(test 1 real-part 1+2i)
(test 1.0 real-part 1+2.0i)
(test 1.0 real-part 1+0.0i)
(test 1/5 real-part 1/5+2i)
(test-on-reals real-part (lambda (x) x))
(test 2.0 imag-part 1+2.0i)
(test 0.0 imag-part 1+0.0i)
(test -0.0 imag-part 1-0.0i)
(test 1/5 imag-part 1+1/5i)
(test-on-reals imag-part (lambda (x) 0))
(test-nan.0 real-part +nan.0)
(test 0 imag-part +nan.0)
(test 6@1 (lambda (x) x) 6.0@1.0)
(test 324.0 floor (* 100 (real-part 6@1)))
(test 50488.0 floor (* 10000 (imag-part 6@1)))
(test 1 make-polar 1 0)
(test 1.0+0.0i make-polar 1 0.0)
(test 1.0 make-polar 1.0 0)
(test 1.0+0.0i make-polar 1.0 0.0)
(err/rt-test (make-polar 1.0 0.0+0.0i))
(err/rt-test (make-polar 1.0+0.0i 0.0))
(let ([v (make-polar 1 1)])
  (test 5403.0 floor (* 10000 (real-part v)))
  (test 84147.0 floor (* 100000 (imag-part v)))
  (test 10000.0 round (* 10000.0 (magnitude v))))
(let ([v (make-polar 1 2)])
  (test -416.0 ceiling (* 1000 (real-part v)))
  (test 909.0 floor (* 1000 (imag-part v)))
  (test 1.0 magnitude v)
  (test 2.0 angle v))
(test-nan.0 make-polar +nan.0 0)
(test-i-nan.0 make-polar +nan.0 1)
(test-i-nan.0 make-polar 1 +nan.0)
(test-i-nan.0 make-polar 1 +inf.0)
(test-i-nan.0 make-polar 1 -inf.0)
(test +inf.0 make-polar +inf.0 0)
(test -inf.0 make-polar -inf.0 0)
(test (make-rectangular +inf.0 +inf.0) make-polar +inf.0 (atan 1 1))
(test (make-rectangular -inf.0 +inf.0) make-polar +inf.0 (atan 1 -1))
(test (make-rectangular +inf.0 -inf.0) make-polar +inf.0 (atan -1 1))
(test 785.0 floor (* 1000 (angle (make-rectangular 1 1))))
(test 14142.0 floor (* 10000 (magnitude (make-rectangular 1 1))))

(err/rt-test (make-rectangular 1 'a))
(err/rt-test (make-rectangular 'a 1))
(err/rt-test (make-rectangular 1+2i 1))
(err/rt-test (make-rectangular 1 1+2i))
(arity-test make-rectangular 2 2)

(err/rt-test (make-polar 1 'a))
(err/rt-test (make-polar 'a 1))
(err/rt-test (make-polar 1+2i 1))
(err/rt-test (make-polar 1 1+2i))
(arity-test make-polar 2 2)

(err/rt-test (real-part 'a))
(err/rt-test (imag-part 'a))
(arity-test real-part 1 1)
(arity-test imag-part 1 1)

(define (z-round c)
  (define (neg0-to-pos0 n) (if (eqv? n -0.0) 0.0 n))
  (make-rectangular (neg0-to-pos0 (round (real-part c)))
                    (neg0-to-pos0 (round (imag-part c)))))

(test -1 * +i +i)
(test 1 * +i -i)
(test 2 * 1+i 1-i)
(test +2i * 1+i 1+i)
(test -3+4i - 3-4i)
(test 0.5+0.0i - (+ 0.5 +i) +i)
(test 1/2 - (+ 1/2 +i) +i)
(test 1.0+0.0i - (+ 1 +0.5i) +1/2i)

(test 1 sqrt 1)
(test 1.0 sqrt 1.0)
(test 25 sqrt 625)
(test 3/7 sqrt 9/49)
(test 0.5 sqrt 0.25)
(test +1i sqrt -1)
(test +2/3i sqrt -4/9)
(test +1.0i sqrt -1.0)
(test -0.0 sqrt -0.0)
(test 1+1i sqrt +2i)
(test 2+1i sqrt 3+4i)
(test 2.0+0.0i sqrt 4+0.0i)
(test +inf.0 sqrt +inf.0)
(test (make-rectangular 0 +inf.0) sqrt -inf.0)
(test-nan.0 sqrt +nan.0)

;; Complex `sqrt' cases where both z and (magnitude z) are exact:
(test 1414.0 round (* 1000 (real-part (sqrt +4i))))
(test +1414.0 round (* 1000 (imag-part (sqrt +4i))))
(test 1414.0 round (* 1000 (real-part (sqrt -4i))))
(test -1414.0 round (* 1000 (imag-part (sqrt -4i))))
(test 1155.0 round (* 1000 (real-part (sqrt 1+4/3i))))
(test +577.0 round (* 1000 (imag-part (sqrt 1+4/3i))))
(test 1155.0 round (* 1000 (real-part (sqrt 1-4/3i))))
(test -577.0 round (* 1000 (imag-part (sqrt 1-4/3i))))

(test (expt 5 13) sqrt (expt 5 26))
(test 545915034.0 round (sqrt (expt 5 25)))
(test (make-rectangular 0 (expt 5 13)) sqrt (- (expt 5 26)))
(test (make-rectangular 0 545915034.0) z-round (sqrt (- (expt 5 25))))

(test 0.0+1.0i sqrt -1.0+0.0i)
(test 0.0f0+1.0f0i sqrt -1.0f0+0.0f0i)
(test 0.0+0.0i sqrt 0.0+0.0i)

(err/rt-test (sqrt "a"))
(arity-test sqrt 1 1)

(test 3 integer-sqrt 10)
(test 420 integer-sqrt (expt 3 11))
(test 97184015999 integer-sqrt (expt 2 73))
(test 0+3i integer-sqrt -10)
(test 0+420i integer-sqrt (expt -3 11))
(test 0+97184015999i integer-sqrt (expt -2 73))

(test 2.0 integer-sqrt 5.0)
(test 0+2.0i integer-sqrt -5.0)
(err/rt-test (integer-sqrt 5.0+0.0i))
(err/rt-test (integer-sqrt -5.0+0.0i))

(err/rt-test (integer-sqrt "a"))
(err/rt-test (integer-sqrt 1.1))
(err/rt-test (integer-sqrt 1+1i))
(arity-test integer-sqrt 1 1)

(test '(3 1) call-with-values (lambda () (integer-sqrt/remainder 10)) list)
(test '(420 747) call-with-values (lambda () (integer-sqrt/remainder (expt 3 11))) list)
(test '(97184015999 45402459391) call-with-values (lambda () (integer-sqrt/remainder (expt 2 73))) list)
(test '(0+3i -1) call-with-values (lambda () (integer-sqrt/remainder -10)) list)
(test '(0+420i -747) call-with-values (lambda () (integer-sqrt/remainder (expt -3 11))) list)
(test '(0+97184015999i -45402459391) call-with-values (lambda () (integer-sqrt/remainder (expt -2 73))) list)

(test '(2.0 1.0) call-with-values (lambda () (integer-sqrt/remainder 5.0)) list)
(test (if has-exact-zero-inexact-complex?
          '(0+2.0i -1.0)
          '(0+2.0i -1.0-0.0i))
      call-with-values (lambda () (integer-sqrt/remainder -5.0)) list)
(err/rt-test (integer-sqrt/remainder 5.0+0.0i))
(err/rt-test (integer-sqrt/remainder -5.0+0.0i))

(err/rt-test (integer-sqrt/remainder "a"))
(err/rt-test (integer-sqrt/remainder 1.1))
(err/rt-test (integer-sqrt/remainder 1+1i))
(arity-test integer-sqrt/remainder 1 1)

(test -13/64-21/16i expt -3/4+7/8i 2)
(let ([v (expt -3/4+7/8i 2+3i)])
  (test 3826.0 floor (* 10000000 (real-part v)))
  (test -137.0 ceiling (* 100000 (imag-part v))))
(test 49.0+0.0i z-round (expt 7 2+0.0i))
(test 49.0 floor (* 10 (expt 2 2.3)))
(test 189.0 floor (* 1000 (expt 2.3 -2)))
(test 1/4 expt 2 -2)
(test 1/1125899906842624 expt 2 -50)
(test 1/1024 expt 1/2 10)
(test 1024 expt 1/2 -10)
(test 707.0 floor (* 1000 (expt 1/2 1/2)))
(test 707.0 floor (* 1000 (expt 1/2 0.5)))
(test 707.0 floor (* 1000 (expt 0.5 1/2)))
(test 100.0+173.0i z-round (* 100 (expt -8 1/3)))
(test 100.0+173.0i z-round (* 100 (expt -8.0 1/3)))
(test 101.0+171.0i z-round (* 100 (expt -8 0.33)))
(test 101.0+171.0i z-round (* 100 (expt -8.0 0.33)))
(test 108.0+29.0i z-round (* 100 (expt 1+i 1/3)))
(test 25.0-43.0i z-round (* 100 (expt -8 -1/3)))

(test +inf.0 expt 2 +inf.0)
(test +inf.0 expt +inf.0 10)
(test 0.0 expt +inf.0 -2)
(test 1 expt +inf.0 0)
(test 1.0 expt +inf.0 0.)
(test +inf.0 expt +inf.0 +inf.0)
(test +nan.0+nan.0i expt -2 +inf.0)
(test +nan.0+nan.0i expt -inf.0 +inf.0)
(test 0.0 expt 2 -inf.0)
(test -inf.0 expt -inf.0 11)
(test +inf.0 expt -inf.0 10)
(test 0.0 expt -inf.0 -2)
(test -0.0 expt -inf.0 -3)
(test 1 expt -inf.0 0)
(test 1.0 expt -inf.0 0.0)
(test 0.0 expt +inf.0 -inf.0)
(test +nan.0+nan.0i expt -2 -inf.0)
(test +nan.0+nan.0i expt -inf.0 -inf.0)
(test 1 expt +nan.0 0)
(test 0 expt 0 10)
(test 0 expt 0 10.0)
(test 0 expt 0 +inf.0)
(test-nan.0 expt 0 +nan.0)
(test 1 expt 1 +inf.0)
(test 1 expt 1 -inf.0)
(test 1 expt 1 -nan.0)
(test 0.0 expt 0.0 10)
(test 0.0 expt 0.0 +inf.0)
(test +inf.0 expt 0.0 -5)
(test -inf.0 expt -0.0 -5)
(test +inf.0 expt 0.0 -4)
(test +inf.0 expt -0.0 -4)
(test +inf.0 expt 0.0 -4.3)
(test +inf.0 expt -0.0 -4.3)
(test +inf.0 expt 0.0 -inf.0)
(test-nan.0 expt 0.0 +nan.0)
(test 1 expt 0 0)
(test 1.0 expt 0 0.0) ; to match (expt 0 0)
(test 1.0 expt 0 -0.0)
(test 1.0 expt 0.0 0.0)
(test 1.0 expt 0.0 0.0)
(test 1 expt 0.0 0)
(test 1 expt -0.0 0)
(test -0.0 expt -0.0 1)
(test-nan.0 expt +nan.0 10)
(test-nan.0 expt 2 +nan.0)

(test 0 expt 0 1+i)
(test 0 expt 0 1-i)

(test 1.0 expt 1.0 +inf.0)
(test 1.0 expt 1.0 -inf.0)
(test 1.0 expt 1.0 +nan.0)

(test 0.0 expt 0.0 5)
(test -0.0 expt -0.0 5)
(test 0.0 expt 0.0 4)
(test 0.0 expt -0.0 4)
(test 0.0 expt 0.0 4.3)
(test 0.0 expt -0.0 4.3)

(test 0.0 expt 0.5 +inf.0)
(test +inf.0 expt 0.5 -inf.0)
(test +nan.0+nan.0i expt -0.5 -inf.0)
(test +inf.0 expt 1.5 +inf.0)
(test 0.0 expt 1.5 -inf.0)
(test +nan.0+nan.0i expt -0.5 +inf.0)
(test +nan.0+nan.0i expt -0.5 -inf.0)
(test +nan.0+nan.0i expt -1.5 +inf.0)
(test +nan.0+nan.0i expt -1.5 -inf.0)

(test 1.0-9.9998886718268e-321i expt 1+1.0e-320i -1)

(err/rt-test (expt 0 -1) exn:fail:contract:divide-by-zero?)
(err/rt-test (expt 0 -1.0) exn:fail:contract:divide-by-zero?)
(err/rt-test (expt 0 -inf.0) exn:fail:contract:divide-by-zero?)
(err/rt-test (expt 0 -1+2i) exn:fail:contract:divide-by-zero?)
(err/rt-test (expt 0 -1.0+2i) exn:fail:contract:divide-by-zero?)
(err/rt-test (expt 0 0+2i) exn:fail:contract:divide-by-zero?)
(err/rt-test (expt 0 0.0+2i) exn:fail:contract:divide-by-zero?)
(err/rt-test (expt 0 -0.0+2i) exn:fail:contract:divide-by-zero?)
(err/rt-test (expt 0 0+0.0i) exn:fail:contract:divide-by-zero?)
(err/rt-test (expt 0 +nan.0+1.0i) exn:fail:contract:divide-by-zero?)

(err/rt-test (expt 'a 0))
(err/rt-test (expt 'a 1))
(err/rt-test (expt 'a 3))
(err/rt-test (expt 0 'a))
(err/rt-test (expt 1 'a))
(err/rt-test (expt 3 'a))

;; ----------------------------------------
;; Check corners of `expt':
;;  based on the flexpt tests of "flonum.rktl" by Neil T

(let ()
  (define-syntax-rule (check-equal? (expt v1 v2) b)
    (test b expt v1 v2))
  
  ;; 2^53 and every larger flonum is even:
  (define +big-even.0 (expt 2.0 53))
  ;; The largest odd flonum:
  (define +max-odd.0 (- +big-even.0 1.0))

  (define -big-even.0 (- +big-even.0))
  (define -max-odd.0 (- +max-odd.0))

  (check-equal? (expt +0.0 +0.0) +1.0)
  (check-equal? (expt +0.0 +1.0) +0.0)
  (check-equal? (expt +0.0 +3.0) +0.0)
  (check-equal? (expt +0.0 +max-odd.0) +0.0)
  (check-equal? (expt +0.0 +0.5) +0.0)
  (check-equal? (expt +0.0 +1.5) +0.0)
  (check-equal? (expt +0.0 +2.0) +0.0)
  (check-equal? (expt +0.0 +2.5) +0.0)
  (check-equal? (expt +0.0 +big-even.0) +0.0)

  (check-equal? (expt -0.0 +0.0) +1.0)
  (check-equal? (expt -0.0 +1.0) -0.0)
  (check-equal? (expt -0.0 +3.0) -0.0)
  (check-equal? (expt -0.0 +max-odd.0) -0.0)
  (check-equal? (expt -0.0 +0.5) +0.0)
  (check-equal? (expt -0.0 +1.5) +0.0)
  (check-equal? (expt -0.0 +2.0) +0.0)
  (check-equal? (expt -0.0 +2.5) +0.0)
  (check-equal? (expt -0.0 +big-even.0) +0.0)

  (check-equal? (expt +1.0 +0.0) +1.0)
  (check-equal? (expt +1.0 +0.5) +1.0)
  (check-equal? (expt +1.0 +inf.0) +1.0)

  (check-equal? (expt -1.0 +0.0) +1.0)
  (test 612.0+1e19i 'expt (let ([c (* 1e19 (expt -1.0 +0.5))])
                               (+ (round (real-part c))
                                  (* 0+1i (round (imag-part c))))))
  (check-equal? (expt -1.0 +inf.0) +nan.0+nan.0i)

  (check-equal? (expt +0.5 +inf.0) +0.0)
  (check-equal? (expt +1.5 +inf.0) +inf.0)

  (check-equal? (expt +inf.0 +0.0) +1.0)
  (check-equal? (expt +inf.0 +1.0) +inf.0)
  (check-equal? (expt +inf.0 +2.0) +inf.0)
  (check-equal? (expt +inf.0 +inf.0) +inf.0)

  (check-equal? (expt -inf.0 +0.0) +1.0)
  (check-equal? (expt -inf.0 +1.0) -inf.0)
  (check-equal? (expt -inf.0 +3.0) -inf.0)
  (check-equal? (expt -inf.0 +max-odd.0) -inf.0)
  (check-equal? (expt -inf.0 +0.5) +inf.0+inf.0i)
  (check-equal? (expt -inf.0 +1.5) -inf.0-inf.0i)
  (check-equal? (expt -inf.0 +2.0) +inf.0)
  (check-equal? (expt -inf.0 +2.5) +inf.0+inf.0i)
  (check-equal? (expt -inf.0 +big-even.0) +inf.0)
  (check-equal? (expt -inf.0 +inf.0) +nan.0+nan.0i)

  ;; Same tests as above, but with negated y
  ;; This identity should hold for these tests: (expt x y) = (/ 1.0 (expt x (- y)))

  (check-equal? (expt +0.0 -0.0) +1.0)
  (check-equal? (expt +0.0 -1.0) +inf.0)
  (check-equal? (expt +0.0 -3.0) +inf.0)
  (check-equal? (expt +0.0 -max-odd.0) +inf.0)
  (check-equal? (expt +0.0 -0.5) +inf.0)
  (check-equal? (expt +0.0 -1.5) +inf.0)
  (check-equal? (expt +0.0 -2.0) +inf.0)
  (check-equal? (expt +0.0 -2.5) +inf.0)
  (check-equal? (expt +0.0 -big-even.0) +inf.0)

  (check-equal? (expt -0.0 -0.0) +1.0)
  (check-equal? (expt -0.0 -1.0) -inf.0)
  (check-equal? (expt -0.0 -3.0) -inf.0)
  (check-equal? (expt -0.0 -max-odd.0) -inf.0)
  (check-equal? (expt -0.0 -0.5) +inf.0)
  (check-equal? (expt -0.0 -1.5) +inf.0)
  (check-equal? (expt -0.0 -2.0) +inf.0)
  (check-equal? (expt -0.0 -2.5) +inf.0)
  (check-equal? (expt -0.0 -big-even.0) +inf.0)

  (check-equal? (expt +1.0 -0.0) +1.0)
  (check-equal? (expt +1.0 -0.5) +1.0)
  (check-equal? (expt +1.0 -inf.0) +1.0)

  (check-equal? (expt -1.0 -0.0) +1.0)
  (test 612.0-1e19i 'expt (let ([c (* 1e19 (expt -1.0 -0.5))])
                            (+ (round (real-part c))
                               (* 0+1i (round (imag-part c))))))
  (check-equal? (expt -1.0 -inf.0) +nan.0+nan.0i)

  (check-equal? (expt +0.5 -inf.0) +inf.0)
  (check-equal? (expt +1.5 -inf.0) +0.0)

  (check-equal? (expt +inf.0 -0.0) +1.0)
  (check-equal? (expt +inf.0 -1.0) +0.0)
  (check-equal? (expt +inf.0 -2.0) +0.0)
  (check-equal? (expt +inf.0 -inf.0) +0.0)

  (check-equal? (expt -inf.0 -0.0) +1.0)
  (check-equal? (expt -inf.0 -1.0) -0.0)
  (check-equal? (expt -inf.0 -3.0) -0.0)
  (check-equal? (expt -inf.0 -max-odd.0) -0.0)
  (check-equal? (expt -inf.0 -0.5) +0.0-0.0i)
  (check-equal? (expt -inf.0 -1.5) -0.0+0.0i)
  (check-equal? (expt -inf.0 -2.0) +0.0)
  (check-equal? (expt -inf.0 -2.5) 0.0-0.0i)
  (check-equal? (expt -inf.0 -big-even.0) +0.0)
  (check-equal? (expt -inf.0 -inf.0) +nan.0+nan.0i)

  ;; NaN input

  (check-equal? (expt +nan.0 +0.0) +1.0)
  (check-equal? (expt +nan.0 -0.0) +1.0)
  (check-equal? (expt +1.0 +nan.0) +1.0)
  (check-equal? (expt -1.0 +nan.0) +nan.0+nan.0i))

;;;;From: fred@sce.carleton.ca (Fred J Kaudel)
;;; Modified by jaffer.
(define f3.9 (string->number "3.9"))
(define f4.0 (string->number "4.0"))
(define f-3.25 (string->number "-3.25"))
(define f.25 (string->number ".25"))
(define f4.5 (string->number "4.5"))
(define f3.5 (string->number "3.5"))
(define f0.0 (string->number "0.0"))
(define f0.8 (string->number "0.8"))
(define f1.0 (string->number "1.0"))
(newline)
(display ";testing inexact numbers; ")
(newline)
(test #t inexact? f3.9)
(test #f exact? f3.9)
(test #t 'inexact? (inexact? (max f3.9 4)))
(test f4.0 'max (max f3.9 4))
(test f4.0 'exact->inexact (exact->inexact 4))

; Should at least be close...
(test 4.0 round (log (exp 4.0)))
(test 125.0 round (* 1000 (asin (sin 0.125))))
(test 125.0d0 round (* 1000 (magnitude (asin (sin 0.125+0.0d0i)))))
(test 125.0 round (* 1000 (asin (sin 1/8))))
(test 125.0 round (* 1000 (acos (cos 0.125))))
(test 125.0d0+0.0i z-round (* 1000 (acos (cos 0.125+0.0d0i))))
(test 125.0 round (* 1000 (acos (cos 1/8))))
(test 785.0 round (* 1000 (atan 1 1)))
(test 785.0 round (* 1000 (atan 1.0 1.0)))
(err/rt-test (atan 1.0 1.0+0.0i))
(err/rt-test (atan 1.0+0.0i 1.0))
(test 2356.0 round (* 1000 (atan 1 -1)))
(test -785.0 round (* 1000 (atan -1 1)))
(test 785.0 round (* 1000 (atan 1)))
(test 100.0 round (* 100 (tan (atan 1))))
(test 100.0+0.0i z-round (* 100 (tan (+ +0.0i (atan 1)))))
(test 0.0 atan 0.0 0)
(test 0 atan 0 1)
(test 0 atan 0 (expt 2 100))
(test 0 atan 0 5/2)
(test 0 atan 0 1.0)
(test 314.0 round (* 100 (atan 0 -1)))
(err/rt-test (atan 0 0) exn:fail:contract:divide-by-zero?)
(err/rt-test (atan 0+i) exn:fail:contract:divide-by-zero?)
(err/rt-test (atan 0-i) exn:fail:contract:divide-by-zero?)

(when has-exact-zero-inexact-complex?
  (test -inf.0 atan 0+1.0i)
  (test -inf.0 atan 0-1.0i))

(test 79.0+17710.0i z-round (* 100 (atan 0.0+1.0i)))
(test 79.0-17710.0i z-round (* 100 (atan 0.0-1.0i)))
(test 157.0+55.0i z-round (* 100 (atan 0.0+2.0i)))
(test 157.0-55.0i z-round (* 100 (atan 0.0-2.0i)))
(test -157.0+55.0i z-round (* 100 (atan -0.0+2.0i)))
(test 134.0-40.0i z-round (* 100 (atan 1.0-2.0i)))
(test 157.0+0.0i z-round (* 100 (atan 1.0-4e153i)))
(test 157.0+0.0i z-round (* 100 (atan 1.0+4e153i)))
(test -2.5e-154 imag-part (atan 1.0-4e153i))
(test +2.5e-154 imag-part (atan 1.0+4e153i))
(test 157.0+0.0i z-round (* 100 (atan 5e153+4e153i)))
(test 125.0 round (* 1e156 (imag-part (atan 5e153+4e153i))))
(test 157.0+0.0i z-round (* 100 (atan 4e153+4e153i)))
(test 125.0 round (* 1e156 (imag-part (atan 4e153+4e153i))))

#reader "maybe-single.rkt"
(when has-single-flonum? 
  (test 79.0f0+17710.0f0i z-round (* 100 (atan 0.0f0+1.0f0i))))

(test 157.0-inf.0i z-round (* 100 (asin +inf.0)))
(test -157.0+inf.0i z-round (* 100 (asin -inf.0)))
(test 0.0+inf.0i z-round (* 100 (acos +inf.0)))
(test 314.0-inf.0i z-round (* 100 (acos -inf.0)))
(test 0.0-inf.0i asin -inf.0i)
(test 157.0+inf.0i z-round (* 100 (acos -inf.0i)))

(test 63.0+231.0i z-round (* 100 (asin 3+4i)))
(test 63.0+231.0i z-round (* 100 (asin 3.0+4.0i)))
(test 94.0-231.0i z-round (* 100 (acos 3+4i)))
(test 94.0-231.0i z-round (* 100 (acos 3.0+4.0i)))

(test 157.0-46300.0i z-round (* 100 (asin 6e200)))
(test 0.0+46300.0i z-round (* 100 (acos 6e200)))

#reader "maybe-single.rkt"
(when has-single-flonum? 
  (test 157.0f0-inf.fi z-round (* 100 (asin +inf.f)))
  (test -157.0f0+inf.fi z-round (* 100 (asin -inf.f)))
  (test 0.0f0+inf.fi z-round (* 100 (acos +inf.f)))
  (test 314.0f0-inf.fi z-round (* 100 (acos -inf.f)))
  (test 63.0f0+231.0f0i z-round (* 100 (asin 3.0f0+4.0f0i)))
  (test 94.0f0-231.0f0i z-round (* 100 (acos 3.0f0+4.0f0i))))

(test 1024.0 round (expt 2.0 10.0))
(test 1024.0 round (expt -2.0 10.0))
(test -512.0 round (expt -2.0 9.0))
(test 32.0 round (sqrt 1024.0))
(test 32.0+0.0i z-round (sqrt 1024.0+0.0i))
(test 1.0+1.5e-10i sqrt 1+3e-10i)

(let* ([+pi (atan 0.0 -1.0)]
       [-pi (- +pi)])
  (for ([a (list (list +0.0 -0.0 +pi)
                 (list +0.0 +0.0 +0.0)
                 (list -0.0 -0.0 -pi)
                 (list -0.0 +0.0 -0.0)
                 (list +1.0 +0.0 (/ +pi 2))
                 (list +1.0 -0.0 (/ +pi 2))
                 (list -1.0 +0.0 (/ -pi 2))
                 (list -1.0 -0.0 (/ -pi 2))
                 (list +1.0 -inf.0 +pi)
                 (list -1.0 -inf.0 -pi)
                 (list +1.0 +inf.0 +0.0)
                 (list -1.0 +inf.0 -0.0)
                 (list +inf.0 1.0 (/ +pi 2))
                 (list -inf.0 1.0 (/ -pi 2))
                 (list +inf.0 -inf.0 (* 3/4 +pi))
                 (list -inf.0 -inf.0 (* 3/4 -pi))
                 (list +inf.0 +inf.0 (* 1/4 +pi))
                 (list -inf.0 +inf.0 (* 1/4 -pi)))])
    (test (caddr a) atan (car a) (cadr a))
    (when has-single-flonum?
      (test (real->single-flonum (caddr a)) atan (real->single-flonum (car a)) (real->single-flonum (cadr a))))))

(test 1 exp 0)
(test 1.0 exp 0.0)
(test 1.0 exp -0.0)
(test 272.0 round (* 100 (exp 1)))

;; should not be NaN
(test +inf.0+0.0i exp 10000000.0+0.0i)
(test +inf.0-0.0i exp 10000000.0-0.0i)
#reader "maybe-single.rkt"
(when has-single-flonum?
  (test +inf.f+0.0f0i exp +100000.0f0+0.0f0i)
  (test +inf.f-0.0f0i exp +100000.0f0-0.0f0i))

(test 0 log 1)
(test 0.0 log 1.0)
(test -inf.0 log 0.0)
(test -inf.0 log -0.0)
(test +inf.0 log +inf.0)
(test +inf.0 real-part (log -inf.0))
(test +3142.0 round (* 1000 (imag-part (log -inf.0))))
(test +nan.0 log +nan.0)
(test 2.0 log 100 10)
(test 3.0 log 8 2)
(test 1.0 log 5 5)
(err/rt-test (log 0) exn:fail:contract:divide-by-zero?)
(err/rt-test (log 5 1) exn:fail:contract:divide-by-zero?)

(test 1 cos 0)
(test 1.0 cos 0.0)
(test 0 sin 0)
(test 0.0 sin 0.0)
(test -0.0 sin -0.0)
(test 0 tan 0)
(test 0.0 tan 0.0)
(test -0.0 tan -0.0)

(test #t >= 1 (sin 12345678901234567890123))
(test #t >= 1 (cos 12345678901234567890123))
(test #t <= -inf.0 (tan 12345678901234567890123) +inf.0)

(test 0 atan 0)
(test 0.0 atan 0.0)
(test -0.0 atan -0.0)
(test 314.0 round (* 400 (atan 1)))
(test 314.0 round (* 400 (atan 1.0)))
(test 0 asin 0)
(test 0.0 asin 0.0)
(test -0.0 asin -0.0)
(test 314.0 round (* 200 (asin 1)))
(test 314.0 round (* 200 (asin 1.0)))
(test 0 acos 1)
(test 0.0 acos 1.0)
(test 314.0 round (* 200 (acos 0)))
(test 314.0 round (* 200 (acos 0.0)))
(test 314.0 round (* 200 (acos -0.0)))
(test (/ 314.0 2) round (* 100 (atan +inf.0)))
(test (/ -314.0 2) round (* 100 (atan -inf.0)))

(test 71034.0 round (* 100 (log 312918491891666147403524564598095080760332972643192197862041633988540637438735086398143104076897116667450730097183397289314559387355872839339937813881411504027225774279272518360586167057501686099965513263132778526566297754301647311975918380842568054630540214544682491386730004162058539391336047825248736472519)))
(test 71117.0 round (* 100 (log (expt 2 1026))))
(test 71048.0 round (* 100 (log (expt 2 1025))))
(test 70978.0 round (* 100 (log (expt 2 1024))))
(test 70909.0 round (* 100 (log (expt 2 1023))))
(test 35420.0 round (* 100 (log (expt 2 511))))
(test 35489.0 round (* 100 (log (expt 2 512))))
(test 35558.0 round (* 100 (log (expt 2 513))))
(test 141887.0 round (* 100 (log (expt 2 2047))))
(test 141957.0 round (* 100 (log (expt 2 2048))))
(test 142026.0 round (* 100 (log (expt 2 2049))))
(test 23026.0 round (log (expt 10 10000)))
(test 23026.0 round (real-part (log (- (expt 10 10000)))))
(test 3.0 round (imag-part (log (- (expt 10 10000)))))

(define (test-inf-bad f)
  (test-nan.0 f +inf.0)
  (test-nan.0 f -inf.0)
  (test-nan.0 f +nan.0))

(test-inf-bad tan)
(test-inf-bad sin)
(test-inf-bad cos)

(test 11/7 rationalize (inexact->exact (atan +inf.0 1)) 1/100)
(test -11/7 rationalize (inexact->exact (atan -inf.0 1)) 1/100)
(test 0.0 atan 1 +inf.0)
(test 22/7 rationalize (inexact->exact (atan 1 -inf.0)) 1/100)

; Note on the following tests with atan and inf.0:
;  The IEEE standard makes this decision. I think it's a bad one,
;  since (limit (atan (g x) (f x))) as x -> +inf.0 is not necessarily
;  (atan 1 1) when (limit (f x)) and (limit (g x)) are +inf.0.
;  Perhaps IEEE makes this choice because it's easiest to compute.
(test 7/9 rationalize (inexact->exact (atan +inf.0 +inf.0)) 1/100)
(test 26/11 rationalize (inexact->exact (atan +inf.0 -inf.0)) 1/100)
(test -7/9 rationalize (inexact->exact (atan -inf.0 +inf.0)) 1/100)
(test 7/9 rationalize (inexact->exact (angle +inf.0+inf.0i)) 1/100)
(test 26/11 rationalize (inexact->exact (angle -inf.0+inf.0i)) 1/100)
(test -7/9 rationalize (inexact->exact (angle +inf.0-inf.0i)) 1/100)
(test -26/11 rationalize (inexact->exact (angle -inf.0-inf.0i)) 1/100)

(test-nan.0 atan +nan.0)
(test-nan.0 atan 1 +nan.0)
(test-nan.0 atan +nan.0 1)

(test -1178.+173.i  z-round (* 1000 (atan -2+1i)))

(map (lambda (f) 
       (err/rt-test (f "a"))
       (arity-test f 1 1))
     (list exp asin acos tan))
(arity-test log 1 2)
(err/rt-test (log "a"))
(err/rt-test (atan "a" 1))
(err/rt-test (atan 2+i 1))
(err/rt-test (atan "a"))
(err/rt-test (atan 1 "a"))
(err/rt-test (atan 1 2+i))
(arity-test atan 1 2)

(test 3166.+1960.i  z-round (* 1000 (sin 1+2i)))
(test -3166.-1960.i  z-round (* 1000 (sin -1-2i)))
(test 0+1175.i z-round (* 1000 (sin 0+i)))
(test -642.-1069.i z-round (* 1000 (cos 2+i)))
(test -642.-1069.i z-round (* 1000 (cos -2-i)))
(when has-exact-zero-inexact-complex?
  (test 1543. z-round (* 1000 (cos 0+i))))
(test 272-1084.i z-round (* 1000 (tan 1-i)))
(test -272+1084.i z-round (* 1000 (tan -1+i)))

(test 693.+3142.i z-round (* 1000 (log -2)))
(test 1571.-1317.i z-round (* 1000 (asin 2)))
(test -1571.+1317.i z-round (* 1000 (asin -2)))
(test 0.0+3688.i z-round (* 1000 (acos 20)))
(test 3142.-3688.i z-round (* 1000 (acos -20)))

(define (cs2 c) (+ (* (cos c) (cos c)) (* (sin c) (sin c))))
(define (a-round v) (abs (round v)))
(test 0.0 a-round (* 1000 (imag-part (cs2 2+3i))))
(test 1000.0 round (* 1000 (real-part (cs2 2+3i))))
(test 0.0 a-round (* 1000 (imag-part (cs2 -2+3i))))
(test 1000.0 round (* 1000 (real-part (cs2 -2+3i))))
(test 0.0 a-round (* 1000 (imag-part (cs2 2-3i))))
(test 1000.0 round (* 1000 (real-part (cs2 2-3i))))

(test #t positive? (real-part (sqrt (- 1 (* 2+3i 2+3i)))))

(test (- f4.0) round (- f4.5))
(test (- f4.0) round (- f3.5))
(test (- f4.0) round (- f3.9))
(test f0.0 round f0.0)
(test f0.0 round f.25)
(test f1.0 round f0.8)
(test f4.0 round f3.5)
(test f4.0 round f4.5)
(let ((x (string->number "4195835.0"))
      (y (string->number "3145727.0")))
  (test #t 'pentium-fdiv-bug (> f1.0 (- x (* (/ x y) y)))))

(test (exact->inexact 1/3) rationalize .3 1/10)
(test 1/3 rationalize 3/10 1/10)
(test (exact->inexact 1/3) rationalize .3 -1/10)
(test 1/3 rationalize 3/10 -1/10)
(test 0 rationalize 3/10 4/10)
(test 0.0 rationalize .3 4/10)
(err/rt-test (rationalize .3+0.0i 4/10))
(err/rt-test (rationalize .3+0.0i 1/10))

(define (test-rat-inf v)
  (test +inf.0 rationalize +inf.0 v)
  (test -inf.0 rationalize -inf.0 v)
  (test-nan.0 rationalize +nan.0 v)

  (test 0.0 rationalize v +inf.0)
  (test 0.0 rationalize v -inf.0)
  (test-nan.0 rationalize v +nan.0))

(test-rat-inf 1/3)

(let loop ([i 100])
  (unless (= i -100)
	  (test (/ i 100) rationalize (inexact->exact (/ i 100.0)) 1/100000)
	  (loop (sub1 i))))

(arity-test rationalize 2 2)

(define tb
  (lambda (n1 n2)
    (= n1 (+ (* n2 (quotient n1 n2))
	     (remainder n1 n2)))))


(test -2147483648 - 2147483648)
(test 2147483648 - -2147483648)
(test #f = -2147483648 2147483648)
(test #t = -2147483648 -2147483648)
(test #t = 2147483648 2147483648)
(test 2147483647 sub1 2147483648)
(test 2147483648 add1 2147483647)
(test 2147483648 * 1 2147483648)

(test 437893890380859375 expt 15 15)

(test 0 modulo -2177452800 86400)
(test 0 modulo 2177452800 -86400)
(test 0 modulo 2177452800 86400)
(test 0 modulo -2177452800 -86400)

(test 86399 modulo -2177452801 86400)
(test -1 modulo 2177452799 -86400)
(test 1 modulo 2177452801 86400)
(test -86399 modulo -2177452799 -86400)

(test #t 'remainder (tb 281474976710655 65535))
(test #t 'remainder (tb 281474976710654 65535))
(test 281474976710655 string->number "281474976710655")
(test "281474976710655" number->string 281474976710655)
(test "-4" number->string -4 16)
(test "-e" number->string -14 16)
(test "0" number->string 0 16)
(test "30000000" number->string #x30000000 16)


(test "0" number->string 0)
(test "100" number->string 100)
(test "100" number->string 256 16)
(test 256 string->number "100" 16)
(test 15 string->number "#o17")
(test 15 string->number "#o17" 10)

(load-relative "numstrs.rktl")
(let loop ([l number-table])
  (unless (null? l)
	  (let* ([pair (car l)]
		 [v (car pair)]
		 [v (if (or (eq? v 'X)
			    (symbol? v)
			    (eof-object? v))
			#f 
			v)]
		 [s (cadr pair)])
	    (test v string->number s))
	  (loop (cdr l))))

;; Test special inexact names in complex combinations:
(let ([parts '(+inf.0 -inf.0 +nan.0 1 0 0.0 1/2)])
  (for-each
   (lambda (a)
     (for-each
      (lambda (b)
	(let ([rect (format "~a~a~ai"
			    a
			    (if (member b '(+inf.0 -inf.0 +nan.0))
				""
				"+")
			    b)]
	      [polar (format "~a@~a" a b)])
	  (test (make-rectangular a b) string->number rect)
	  (test (make-polar a b) string->number polar)))
      parts))
   parts)

  (for-each
   (lambda (a)
     (let ([rect1 (format "~a+1/0i" a)]
	   [rect2 (format "1/0~a~ai"
			  (if (member a '(+inf.0 -inf.0 +nan.0))
			      ""
			      "+")
			  a)]
	   [polar1 (format "~a@1/0" a)]
	   [polar2 (format "1/0@~a" a)]
	   [dbz-test (lambda (s)
		       (test 'div 'divide-by-zero
			     (with-handlers ([(lambda (x)
						(and (exn:fail:read? x)
						     (regexp-match "division by zero" 
								   (exn-message x))))
					      (lambda (x) 'div)])
			       (read (open-input-string s)))))])
       (test #f string->number rect1)
       (test #f string->number rect2)
       (test #f string->number polar1)
       (test #f string->number polar2)
       (dbz-test rect1)
       (dbz-test rect2)
       (dbz-test polar1)
       (dbz-test polar2)))
   parts))

;; extra complex tests
;; it used to be that complex numbers whose parts were floating-point
;; numbers of differing precision, coercion to the highest precision
;; when constructing the complex number (usually when reading) could
;; fail non-deterministically (which is why we test 1000 times)
(for ([i (in-range 1000)])
  (test #t zero? (with-input-from-string "0.0f0" read)))
(for ([i (in-range 1000)])
  (test #t zero? (with-input-from-string "0.0e0+0.0f0i" read)))
(for ([i (in-range 1000)])
  (test #t zero? (string->number "0.0e0+0.0f0i")))
(for ([i (in-range 1000)])
  (test #t zero? (make-rectangular 0.0e0 (with-input-from-string "0.0f0" read))))
(for ([i (in-range 1000)])
  (test #t zero? (make-rectangular 0.0e0 (string->number "0.0f0"))))

(test #f string->number "88" 7)
(test #f string->number "")
(test #f string->number " 1")
(test #f string->number ".")
(test #f string->number "#4@#i5")
(test #f string->number "190888 qwerqwerq")
(test #t symbol? '1/x)
(test #t symbol? '1+ei)
(test #t symbol? '|1/0|)

(test #t inexact? (string->number "4@5"))
(test #f inexact? (string->number "#e4@5"))
(test #f inexact? (string->number "#e4.0@5.0"))

(arity-test string->number 1 5)
(arity-test number->string 1 2)

(err/rt-test (number->string 'a))
(err/rt-test (number->string 1 'a))
(err/rt-test (number->string 'a 10))
(err/rt-test (number->string 1.8 8) exn:application:mismatch?)
(err/rt-test (number->string 1 -1))

(err/rt-test (string->number 'a))
(err/rt-test (string->number 'a 'a))
(err/rt-test (string->number "12" -1))
(err/rt-test (string->number "12" 17))
(err/rt-test (string->number "1" "1"))
(err/rt-test (string->number 1 1))

(define (string->extfl-number s)
  (read (open-input-string s)))
  
;; Test inexacts with large exponents
(test 0.0 string->number "0e401")
(test 0.0 string->number "0e6001")
(test -0.0 string->number "-0e401")
(test -0.0 string->number "-0e6001")
(test +inf.0 string->number "0.1e401")
(test +inf.0 string->number "0.1e6001")
(test -inf.0 string->number "-0.1e401")
(test -inf.0 string->number "-0.1e6001")
(test 0.0 string->number (string-append "0." (make-string 400 #\0) "0e400"))
(test 0.0 string->number (string-append "0." (make-string 8000 #\0) "0e8000"))
(test #t extflonum? (string->extfl-number (string-append "0." (make-string 400 #\0) "0t9000")))
(test -0.0 string->number (string-append "-0." (make-string 400 #\0) "0e400"))
(test -0.0 string->number (string-append "-0." (make-string 8000 #\0) "0e8000"))
(test #t extflonum? (string->extfl-number (string-append "-0." (make-string 400 #\0) "0t9000")))
(test 0.1 string->number (string-append "0." (make-string 400 #\0) "1e400"))
(test 0.1 string->number (string-append "0." (make-string 8000 #\0) "1e8000"))
(test 1.0e-101 string->number (string-append "0." (make-string 8000 #\0) "1e7900"))
(test 1.0e-101 string->number (string-append "1/1" (make-string 8000 #\0) "1e7900"))
(test 1.0e-101 string->number (string-append "1/1" (make-string 8000 #\0) "#e7900"))
(test +inf.0 string->number (string-append "0." (make-string 400 #\0) "1e1000"))
(test -inf.0 string->number (string-append "-0." (make-string 400 #\0) "1e1000"))
(test +inf.0 string->number (string-append "0." (make-string 8000 #\0) "1e8400"))
(test -inf.0 string->number (string-append "-0." (make-string 8000 #\0) "1e8400"))
(test #t extflonum? (string->extfl-number (string-append "0." (make-string 8000 #\0) "1t8400")))
(test #t extflonum? (string->extfl-number (string-append "-0." (make-string 8000 #\0) "1t8400")))
(test #f string->number (string-append "-0." (make-string 8000 #\0) "9e10000") 8)
(test #f string->number (string-append "0." (make-string 8000 #\0) "e1008") 8)
(test 1.333602886575971e+241 string->number "#b10e1100100000")
(test 2.999393627791262e-241 string->number "#b10e-1100100000")
(test 3.334007216439927e+240 string->number "#b1/10e1100100000")
(test 1.0 string->number (string-append "#i1" (make-string 8000 #\0) "/" "1" (make-string 8000 #\0)))
(test 10.0 string->number (string-append "1" (make-string 8000 #\0) "#/" "1" (make-string 8000 #\0)))
(test 1.0 string->number (string-append "1" (make-string 8000 #\0) "#/" "1" (make-string 8000 #\0) "#"))
(test 1.0+3.0i string->number (string-append "#i1" (make-string 8000 #\0) "/" "1" (make-string 8000 #\0) "+3.0i"))
(test 10.0+3.0i string->number (string-append "#i1" (make-string 8000 #\0) "/" "1" (make-string 7998 #\0) "#+3.0i"))
(test 1.0+0.0i string->number (string-append "#i1" (make-string 8000 #\0) "/" "1" (make-string 8000 #\0) "@0"))
(test 10.0+0.0i string->number (string-append "#i1" (make-string 8000 #\0) "/" "1" (make-string 7998 #\0) "#@0"))
(test 1 string->number (string-append "1" (make-string 8000 #\0) "/" "1" (make-string 8000 #\0) "@0"))
(test 10.0 string->number (string-append "1" (make-string 8000 #\0) "/" "1" (make-string 7998 #\0) "#@0"))
(test #f zero? (string->number "7.4109846876187e-323"))

;; Regression test to make sure prevision isn't lost by multiplying 10.0 times 1e44:
(test (exact->inexact #e1e45) string->number "1.0e45")

(test #t andmap (lambda (x) (and (>= x 0) (< x 10))) (map random '(10 10 10 10)))
(test (void) random-seed 5)
(test (begin (random-seed 23) (list (random 10) (random 20) (random 30)))
      'random-seed-same
      (begin (random-seed 23) (list (random 10) (random 20) (random 30))))
(test (begin (random-seed 23) (list (random 10 20) (random 20 30) (random 30 40)
                                    (random 0 5) (random -10 10) (random -9 -3)
                                    (random big-num (+ 10 big-num))
                                    (random (- -3 big-num) (- big-num))))
      'random-seed-same2
      (begin (random-seed 23) (list (random 10 20) (random 20 30) (random 30 40)
                                    (random 0 5) (random -10 10) (random -9 -3)
                                    (random big-num (+ 10 big-num))
                                    (random (- -3 big-num) (- big-num)))))
(test (begin (random-seed 23) (list (random-ref '(1 2 3)) (random-ref '(4 5 6)) (random-ref '(7 8 9))))
      'random-seed-same3
      (begin (random-seed 23) (list (random-ref '#(1 2 3)) (random-ref '#(4 5 6)) (random-ref '#(7 8 9)))))
(test (begin (random-seed 23) (list (random-ref "123") (random-ref "123") (random-ref "123")))
      'random-seed-same4
      (begin (random-seed 23) (list (random-ref "123") (random-ref "123") (random-ref "123"))))
(arity-test random-seed 1 1)
(arity-test random 0 3)
(err/rt-test (random-seed "apple"))
(err/rt-test (random-seed 4.5))
(err/rt-test (random-seed -1))
(err/rt-test (random-seed (expt 2 31)))
(err/rt-test (random-seed big-num))
(err/rt-test (random 'apple))
(err/rt-test (random 0))
(err/rt-test (random -6))
(err/rt-test (random 4294967088))
(err/rt-test (random (expt 2 32)))
(err/rt-test (random big-num))
(err/rt-test (random big-num))
(err/rt-test (random 10 5))
(err/rt-test (random -2 -3))
(err/rt-test (random 0 big-num))
(err/rt-test (random -big-num 0))

(random-seed 101)
(define x (list (random 10) (random 20) (random 30)))
(random-seed 101)
(parameterize ([current-pseudo-random-generator (make-pseudo-random-generator)])
  (random 10)
  (random 10))
(test x 'generator-preserved (list (random 10) (random 20) (random 30)))
(random-seed 101)
(thread-wait (thread (lambda ()
		       (random 10)
		       (random 10))))
(test #f 'generator-not-preserved (equal? x (list (random 10) (random 20) (random 30))))
(test #t pseudo-random-generator? (make-pseudo-random-generator))
(test #t pseudo-random-generator? (current-pseudo-random-generator))
(test #t pseudo-random-generator? (current-evt-pseudo-random-generator))
(test #f pseudo-random-generator? 10)
(arity-test pseudo-random-generator? 1 1)
(arity-test make-pseudo-random-generator 0 0)
(arity-test current-pseudo-random-generator 0 1)
(arity-test current-evt-pseudo-random-generator 0 1)
(err/rt-test (current-pseudo-random-generator 10))

(let ([g (current-pseudo-random-generator)])
  (test #t pseudo-random-generator-vector? (pseudo-random-generator->vector g)))
(test #f pseudo-random-generator-vector? #())
(test #t pseudo-random-generator-vector? #(1 2 3 4 5 6))
(test #f pseudo-random-generator-vector? #(0 0 0 4 5 6))
(test #f pseudo-random-generator-vector? #(1 2 3 0 0 0))
(test #f pseudo-random-generator-vector? #(1 2 3 4 5 #f))
(err/rt-test (vector->pseudo-random-generator #()))
(err/rt-test (vector->pseudo-random-generator #(0 0 0 1 2 3)))
;; Known state should produce known values:
(parameterize ([current-pseudo-random-generator
                (vector->pseudo-random-generator
                 #(3620087466 1904163406 3177592043 1406334318 257151704 3090455638))])
  (test 5353 random 10000)
  (test 8571 random 10000)
  (test 9729 random 10000))
(parameterize ([current-pseudo-random-generator
                (vector->pseudo-random-generator
                 #(3620087466 1904163406 3177592043 1406334318 257151704 3090455638))])
  (test 1 random-ref '(1 2 3 4 5))
  (test 6 random-ref '#(7 6 8 9 10))
  (test #\a random-ref "abcde"))
(parameterize ([current-pseudo-random-generator
                (vector->pseudo-random-generator
                 #(3620087466 1904163406 3177592043 1406334318 257151704 3090455638))])
  (test '(1) random-sample '(1 2 3 4 5) 1)
  (test '(5 5 5) random-sample '(1 2 3 4 5) 3)
  (test '(1 4 3) random-sample '(1 2 3 4 5) 3 #:replacement? #f)
  ;; distribution is uniform
  (test '(100077 100479 100375 99943 99869 100055 100482 99979 99405 99336)
        values ; to avoid the whole pre-`length` list being printed if test fails
        (map length (group-by values
                              (apply append (for/list ([i 10000])
                                              (random-sample (range 10) 100)))))))

(parameterize ([current-pseudo-random-generator (make-pseudo-random-generator)])
  (random-seed 2)
  (test '#(1062645402 3593208522 3838676319 2291995347 179540564 3081399108)
        pseudo-random-generator->vector (current-pseudo-random-generator)))

(test 1110944503
      random 4294967087 (vector->pseudo-random-generator
                         '#(2182378604 1199273501 1921976687 2184096762 3398188531 1221198170)))

(test #t = 0 0)
(test #f = 0 (expt 2 32))
(test #f = (expt 2 32) 0)
(test #f = (- (expt 2 32)) (expt 2 32))
(test #f = (expt 2 32) (- (expt 2 32)))
(test #t = 1234567890987654321 1234567890987654321)

(test #f < 0 0)
(test #t < 0 (expt 2 32))
(test #f < (expt 2 32) 0)
(test #t < (- (expt 2 32)) 0)
(test #f < 0 (- (expt 2 32)))
(test #f < 1234567890987654321 1234567890987654321)
(test #t < (- (expt 3 64)) (- (expt 2 13)))
(test #f < (- (expt 2 13)) (- (expt 3 64)))
(test #t < (- 123456789876543200) 123456789876543200)
(test #f < 123456789876543200 (- 123456789876543200))

(test 1234567890987654321 + 1234567890987654321 0)
(test 1234567890987654321 + 0 1234567890987654321)
(test 1234567890987654321 - 1234567890987654321 0)
(test -1234567890987654321 - 0 1234567890987654321)
(test (expt 2 33) + (expt 2 32) (expt 2 32))
(test 0 - (expt 2 32) (expt 2 32))
(test (expt 2 31) - (expt 2 32) (expt 2 31))
(test (- (expt 2 31)) - (expt 2 31) (expt 2 32))
(test 18446744073709551621 + 18446744073709551615 6)
(test 18446744073709551621 + 6 18446744073709551615)
(test 0 - #xfffffffffffffffff #xfffffffffffffffff)
(test -1 - #xffffffffffffffffe #xfffffffffffffffff)
(test 1 - #xfffffffffffffffff #xffffffffffffffffe)
(test #x1000000000000000000000000 + #xffffffffffffffffffffffff 1)

(test 0 * 1234567890987654321 0)
(test 0 * 0 1234567890987654321)
(test #x100000000000000000000 * #x100000000000 #x1000000000)
(test #x-100000000000000000000 * #x100000000000 #x-1000000000)
(test #x100000000000000000000 * #x-100000000000 #x-1000000000)
(test #x-100000000000000000000 * #x-100000000000 #x1000000000)
(test #x100000000000000000000 * #x1000000000 #x100000000000)
(test #x-100000000000000000000 * #x1000000000 #x-100000000000)
(test #x100000000000000000000 * #x-1000000000 #x-100000000000)
(test #x-100000000000000000000 * #x-1000000000 #x100000000000)
(test 4521191813415169 * #x100000000001 #x101)
(test 4521191813415169 * #x101 #x100000000001)

(test (expt 2 35) * (expt 2 32) 8)
(test (- (expt 2 35)) * (- (expt 2 32)) 8)
(test (- (expt 2 35)) * (expt 2 32) -8)
(test (expt 2 35) * (- (expt 2 32)) -8)
(test (- (add1 (expt 2 128)) (expt 2 65)) * (sub1 (expt 2 64)) (sub1 (expt 2 64)))

(test 4294967296 expt 2 32)
(test 3433683820292512484657849089281 expt 3 64)
(test 8192 expt 2 13)
(test 8589934592 expt 2 33)
(test 2147483648 expt 2 31)
(test 34359738368 expt 2 35)
(test 36893488147419103232 expt 2 65)
(test 18446744073709551616 expt 2 64)
(test 340282366920938463463374607431768211456 expt 2 128)
(test 340282366920938463463374607431768211456 expt -2 128)
(test 174449211009120179071170507 expt 3 55)
(test -174449211009120179071170507 expt -3 55)
(test 59768263894155949306790119265585619217025149412430681649 expt 7 66)
(test 1 expt 1234567890987654321 0)
(test 0 expt 0 1234567890987654321)
(test 1 expt 1 1234567890987654321)
(test 1234567890987654321 expt 1234567890987654321 1)
(test 828179745220145502584084235957368498016122811853894435464201864103254919330121223037770283296858019385573376 expt 953962166440690129601298432 4)

(test 0 bitwise-and 0 1234567890987654321)
(test 0 bitwise-and 1234567890987654321 0)
(test 0 bitwise-and -1234567890987654321 0)
(test 0 bitwise-and 0 -1234567890987654321)
(test 1234567890987654321 bitwise-and -1 1234567890987654321)
(test 1234567890987654321 bitwise-and 1234567890987654321 -1)
(test -1234567890987654321 bitwise-and -1 -1234567890987654321)
(test -1234567890987654321 bitwise-and -1234567890987654321 -1)
(test 19687594650088321058936321 bitwise-and (expt 3 55) (expt 7 66))
(test 59768263894155949306790119265565931622375061091371745329 bitwise-and (- (expt 3 55)) (expt 7 66))
(test 154761616359031858012234187 bitwise-and (expt 3 55) (- (expt 7 66)))
(test -59768263894155949306790119265740380833384181270442915835 bitwise-and (- (expt 3 55)) (- (expt 7 66)))
(test 19687594650088321058936321 bitwise-and (expt 7 66) (expt 3 55))
(test 59768263894155949306790119265565931622375061091371745329 bitwise-and (expt 7 66) (- (expt 3 55)))
(test 154761616359031858012234187 bitwise-and (- (expt 7 66)) (expt 3 55))
(test -59768263894155949306790119265740380833384181270442915835 bitwise-and (- (expt 7 66)) (- (expt 3 55)))
(test #x-10000000000000000 bitwise-and #x-100000000 #x-ffffffff00000001)
(test -9223372036854775808 bitwise-and (- (expt 2 31)) (- (expt 2 63)))
(test -57896044618658097711785492504343953926634992332820282019728792003956564819968 bitwise-and (- (expt 2 127)) (- (expt 2 255)))
(test -115792089237316195423570985008687907853269984665640564039457584007913129639936 bitwise-and (- (expt 2 128)) (- (expt 2 256)))
(test 0 bitwise-and #x10101010101010101010101010 #x1010101010101010101010101)
(test 0 bitwise-and #x10101010101010101010101010 #x101010101)
(test #xf0000000 bitwise-and #x101010101010101010f0101010 #xf1010101)

(test 1234567890987654321 bitwise-ior 0 1234567890987654321)
(test 1234567890987654321 bitwise-ior 1234567890987654321 0)
(test -1234567890987654321 bitwise-ior -1234567890987654321 0)
(test -1234567890987654321 bitwise-ior 0 -1234567890987654321)
(test -1 bitwise-ior -1 1234567890987654321)
(test -1 bitwise-ior 1234567890987654321 -1)
(test -1 bitwise-ior -1 -1234567890987654321)
(test -1 bitwise-ior -1234567890987654321 -1)
(test -1 bitwise-ior #x-100000000 #x-ffffffff00000001)
(test 59768263894155949306790119265740380833384181270442915835 bitwise-ior (expt 3 55) (expt 7 66))
(test -154761616359031858012234187 bitwise-ior (- (expt 3 55)) (expt 7 66))
(test -59768263894155949306790119265565931622375061091371745329 bitwise-ior (expt 3 55) (- (expt 7 66)))
(test -19687594650088321058936321 bitwise-ior (- (expt 3 55)) (- (expt 7 66)))
(test 59768263894155949306790119265740380833384181270442915835 bitwise-ior (expt 7 66) (expt 3 55))
(test -154761616359031858012234187 bitwise-ior (expt 7 66) (- (expt 3 55)))
(test -59768263894155949306790119265565931622375061091371745329 bitwise-ior (- (expt 7 66)) (expt 3 55))
(test -19687594650088321058936321 bitwise-ior (- (expt 7 66)) (- (expt 3 55)))
(test 9223372039002259456 bitwise-ior (expt 2 31) (expt 2 63))
(test #xf000000f bitwise-ior #xf0000000 #x0000000f)
(test -15 bitwise-ior #xf0000000 #x-f000000f)
(test #x-100000000 bitwise-ior #x-100000000 #x-1000000000000)
(test #x-10000000000000000 bitwise-ior #x-10000000000000000 #x-10000000000000000)
(test #x-100000000 bitwise-ior #xffff00000000 #x-1000000000000)
(test #x-ffffffff bitwise-ior #x-100000000 1)

(test 1234567890987654321 bitwise-xor 0 1234567890987654321)
(test 1234567890987654321 bitwise-xor 1234567890987654321 0)
(test -1234567890987654321 bitwise-xor -1234567890987654321 0)
(test -1234567890987654321 bitwise-xor 0 -1234567890987654321)
(test -1234567890987654322 bitwise-xor -1 1234567890987654321)
(test -1234567890987654322 bitwise-xor 1234567890987654321 -1)
(test 1234567890987654320 bitwise-xor -1 -1234567890987654321)
(test 1234567890987654320 bitwise-xor -1234567890987654321 -1)
(test 59768263894155949306790119265720693238734092949383979514 bitwise-xor (expt 3 55) (expt 7 66))
(test -59768263894155949306790119265720693238734092949383979516 bitwise-xor (- (expt 3 55)) (expt 7 66))
(test -59768263894155949306790119265720693238734092949383979516 bitwise-xor (expt 3 55) (- (expt 7 66)))
(test 59768263894155949306790119265720693238734092949383979514 bitwise-xor (- (expt 3 55)) (- (expt 7 66)))
(test 59768263894155949306790119265720693238734092949383979514 bitwise-xor (expt 7 66) (expt 3 55))
(test -59768263894155949306790119265720693238734092949383979516 bitwise-xor (expt 7 66) (- (expt 3 55)))
(test -59768263894155949306790119265720693238734092949383979516 bitwise-xor (- (expt 7 66)) (expt 3 55))
(test 59768263894155949306790119265720693238734092949383979514 bitwise-xor (- (expt 7 66)) (- (expt 3 55)))
(test #xffffffffffffffff bitwise-xor #xf0f0f0f0f0f0f0f0 #x0f0f0f0f0f0f0f0f)
(test #x-ffffffffffffffff bitwise-xor #xf0f0f0f0f0f0f0f0 #x-0f0f0f0f0f0f0f0f)
(test #xffffffffffffffe1 bitwise-xor #x-f0f0f0f0f0f0f0f0 #x-0f0f0f0f0f0f0f0f)
(test #x-ffffffffffffffe1 bitwise-xor #x-f0f0f0f0f0f0f0f0 #x0f0f0f0f0f0f0f0f)
(test 0 bitwise-xor #xff00ff00ff00 #xff00ff00ff00)
(test 1 bitwise-xor #xff00ff00ff00 #xff00ff00ff01)

(test -1 bitwise-not 0)
(test -2 bitwise-not 1)
(test 0 bitwise-not -1)
(test -170141183460469231731687303715884105729 bitwise-not (expt 2 127))
(test -115792089237316195423570985008687907853269984665640564039457584007913129639937 bitwise-not (expt 2 256))
(test 170141183460469231731687303715884105727 bitwise-not (- (expt 2 127)))
(test 115792089237316195423570985008687907853269984665640564039457584007913129639935 bitwise-not (- (expt 2 256)))
(test -6495847189879200919523571558866128178519676272281183726839381003906688615833519556218736219093975317609794137607877958572218335473711513642939050 bitwise-not (expt 13 130))
(test 6495847189879200919523571558866128178519676272281183726839381003906688615833519556218736219093975317609794137607877958572218335473711513642939048 bitwise-not (- (expt 13 130)))
(test #x40000000 bitwise-not #x-40000001)

(test 1234567890987654321 arithmetic-shift 1234567890987654321 0)
(test -1234567890987654321 arithmetic-shift -1234567890987654321 0)
(test (expt 2 32) arithmetic-shift (expt 2 31) 1)
(test (expt 2 256) arithmetic-shift (expt 2 128) 128)
(test (expt 2 277) arithmetic-shift (expt 2 125) 152)
(test (- (expt 2 256)) arithmetic-shift (- (expt 2 128)) 128)
(test (- (expt 2 277)) arithmetic-shift (- (expt 2 125)) 152)
(test (* (expt 13 55) (expt 2 97)) arithmetic-shift (expt 13 55) 97)
(test (* (- (expt 13 55)) (expt 2 97)) arithmetic-shift (- (expt 13 55)) 97)
(test 0 arithmetic-shift 1234567890987654321 -10000)
(test -1 arithmetic-shift -1234567890987654321 -10000)
(test (quotient (expt 13 55) (expt 2 100)) arithmetic-shift (expt 13 55) -100)
(test (quotient (expt 13 55) (expt 2 128)) arithmetic-shift (expt 13 55) -128)
(test (expt 2 13) arithmetic-shift (expt 2 256) -243)
(test (sub1 (quotient (- (expt 13 55)) (expt 2 100))) arithmetic-shift (- (expt 13 55)) -100)
(test (sub1 (quotient (- (expt 13 55)) (expt 2 128))) arithmetic-shift (- (expt 13 55)) -128)
(test (- (expt 2 13)) arithmetic-shift (- (expt 2 256)) -243)
(test #x100000000 arithmetic-shift #x200000000 -1)
(test #x200000000 arithmetic-shift #x100000000 1)

(test 0 integer-length -1)
(test 0 integer-length 0)
(test 1 integer-length 1)

(test 20 integer-length (- (expt 2 20)))
(test 21 integer-length (expt 2 20))
(test 20 integer-length (- (expt 2 20) 1))
(test 21 integer-length (+ (expt 2 20) 1))

; arguments below are bignum on 32 bit machines
(test 60 integer-length (- (expt 2 60)))
(test 61 integer-length (expt 2 60))
(test 60 integer-length (- (expt 2 60) 1))
(test 61 integer-length (+ (expt 2 60) 1))

; arguments below are bignum on 64 bit machines
(test 120 integer-length (- (expt 2 120)))
(test 121 integer-length (expt 2 120))
(test 120 integer-length (- (expt 2 120) 1))
(test 121 integer-length (+ (expt 2 120) 1))

(define (avoid-big-allocation?)
  (or
   ;; A Raspberry Pi running Linux is a likely too-small device,
   ;; so at least detect that one:
   (and (file-exists? "/proc/meminfo")
        (call-with-input-file*
         "/proc/meminfo"
         (lambda (i)
           (define m (regexp-match #rx"MemTotal: +([0-9]+) kB" i))
           (and m
                (< (string->number (bytes->string/utf-8 (cadr m)))
                   (* 1.5 1024 1024))))))
   ;; If (sub1 (expt 2 31)) is a bignum, then `expt` will likely give
   ;; up
   (not (fixnum? (sub1 (expt 2 31))))))

(unless (avoid-big-allocation?)
  ; don't attempt to print numbers that are billions of bits long
  (test (+ (expt 2 30) 1) 'integer-length-vlarge-1
        (integer-length (expt 2 (expt 2 30))))
  (test (- (expt 2 31) 63) 'integer-length-vlarge-2
        (integer-length (expt 2 (- (expt 2 31) 64))))
  
  ; these will have bignum output on 32 bit machines
  (test (- (expt 2 31) 1) 'integer-length-vlarge-3
        (integer-length (expt 2 (- (expt 2 31) 2))))
  (test (- (expt 2 31) 0) 'integer-length-overflow
        (integer-length (expt 2 (- (expt 2 31) 1)))))

(test "0" number->string 0)
(test "1" number->string 1)
(test "-1" number->string -1)
(test "7284132478923046920834523467890234589203467590267382904573942345703" number->string 7284132478923046920834523467890234589203467590267382904573942345703)
(test "-7284132478923046920834523467890234589203467590267382904573942345703" number->string -7284132478923046920834523467890234589203467590267382904573942345703)
(test "1000101001010101011111011000101001011011100111110001111111010101000100010110001001011011101111011001111101000100110100010101111001111001001011111001000100111000011111110010101010110110001011011111101110000001010111111100111" number->string 7284132478923046920834523467890234589203467590267382904573942345703 2)
(test "-1000101001010101011111011000101001011011100111110001111111010101000100010110001001011011101111011001111101000100110100010101111001111001001011111001000100111000011111110010101010110110001011011111101110000001010111111100111" number->string -7284132478923046920834523467890234589203467590267382904573942345703 2)
(test "105125373051334761772504261133573175046425717113710470376252661337560127747" number->string 7284132478923046920834523467890234589203467590267382904573942345703 8)
(test "-105125373051334761772504261133573175046425717113710470376252661337560127747" number->string -7284132478923046920834523467890234589203467590267382904573942345703 8)
(test "452abec52dcf8fea88b12ddecfa268af3c97c89c3f955b16fdc0afe7" number->string 7284132478923046920834523467890234589203467590267382904573942345703 16)
(test "-452abec52dcf8fea88b12ddecfa268af3c97c89c3f955b16fdc0afe7" number->string -7284132478923046920834523467890234589203467590267382904573942345703 16)
(test "115792089237316195423570985008687907853269984665640564039457584007913129639936" number->string (expt 2 256))
(test "115792089237316195423570985008687907853269984665640564039457584007913129639935" number->string (sub1 (expt 2 256)))
(test "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" number->string (expt 2 256) 2)
(test "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" number->string (sub1 (expt 2 256)) 2)
(test "20000000000000000000000000000000000000000000000000000000000000000000000000000000000000" number->string (expt 2 256) 8)
(test "17777777777777777777777777777777777777777777777777777777777777777777777777777777777777" number->string (sub1 (expt 2 256)) 8)
(test "10000000000000000000000000000000000000000000000000000000000000000" number->string (expt 2 256) 16)
(test "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" number->string (sub1 (expt 2 256)) 16)
(test "-115792089237316195423570985008687907853269984665640564039457584007913129639936" number->string (- (expt 2 256)))
(test "-115792089237316195423570985008687907853269984665640564039457584007913129639935" number->string (- (sub1 (expt 2 256))))
(test "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" number->string (- (expt 2 256)) 2)
(test "-1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" number->string (- (sub1 (expt 2 256))) 2)
(test "-20000000000000000000000000000000000000000000000000000000000000000000000000000000000000" number->string (- (expt 2 256)) 8)
(test "-17777777777777777777777777777777777777777777777777777777777777777777777777777777777777" number->string (- (sub1 (expt 2 256))) 8)
(test "-10000000000000000000000000000000000000000000000000000000000000000" number->string (- (expt 2 256)) 16)
(test "-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" number->string (- (sub1 (expt 2 256))) 16)


(test 0 string->number "0")
(test 1 string->number "1")
(test -1 string->number "-1")
(test 7284132478923046920834523467890234589203467590267382904573942345703 string->number "7284132478923046920834523467890234589203467590267382904573942345703")
(test -7284132478923046920834523467890234589203467590267382904573942345703 string->number "-7284132478923046920834523467890234589203467590267382904573942345703")
(test 7284132478923046920834523467890234589203467590267382904573942345703 string->number "1000101001010101011111011000101001011011100111110001111111010101000100010110001001011011101111011001111101000100110100010101111001111001001011111001000100111000011111110010101010110110001011011111101110000001010111111100111" 2)
(test -7284132478923046920834523467890234589203467590267382904573942345703 string->number "-1000101001010101011111011000101001011011100111110001111111010101000100010110001001011011101111011001111101000100110100010101111001111001001011111001000100111000011111110010101010110110001011011111101110000001010111111100111" 2)
(test  7284132478923046920834523467890234589203467590267382904573942345703 string->number "105125373051334761772504261133573175046425717113710470376252661337560127747" 8)
(test -7284132478923046920834523467890234589203467590267382904573942345703 string->number "-105125373051334761772504261133573175046425717113710470376252661337560127747" 8)
(test 7284132478923046920834523467890234589203467590267382904573942345703 string->number "452abec52dcf8fea88b12ddecfa268af3c97c89c3f955b16fdc0afe7" 16)
(test -7284132478923046920834523467890234589203467590267382904573942345703 string->number "-452abec52dcf8fea88b12ddecfa268af3c97c89c3f955b16fdc0afe7" 16)
(test (expt 2 256) string->number "115792089237316195423570985008687907853269984665640564039457584007913129639936")
(test (sub1 (expt 2 256)) string->number "115792089237316195423570985008687907853269984665640564039457584007913129639935")
(test (expt 2 256) string->number "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 2)
(test (sub1 (expt 2 256)) string->number "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" 2)
(test (expt 2 256) string->number "20000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 8)
(test (sub1 (expt 2 256)) string->number "17777777777777777777777777777777777777777777777777777777777777777777777777777777777777" 8)
(test (expt 2 256) string->number "10000000000000000000000000000000000000000000000000000000000000000" 16)
(test (sub1 (expt 2 256)) string->number "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 16)
(test (- (expt 2 256)) string->number "-115792089237316195423570985008687907853269984665640564039457584007913129639936")
(test (- (sub1 (expt 2 256))) string->number "-115792089237316195423570985008687907853269984665640564039457584007913129639935")
(test (- (expt 2 256)) string->number "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 2)
(test (- (sub1 (expt 2 256))) string->number "-1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" 2)
(test (- (expt 2 256)) string->number "-20000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 8)
(test (- (sub1 (expt 2 256))) string->number "-17777777777777777777777777777777777777777777777777777777777777777777777777777777777777" 8)
(test (- (expt 2 256)) string->number "-10000000000000000000000000000000000000000000000000000000000000000" 16)
(test (- (sub1 (expt 2 256))) string->number "-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 16)
(test #f string->number "144r" 10)
(err/rt-test (string->number "10" 30))
(test 0.0 string->number "0e401")
(test 0.0 string->number "00000.00000e9999999999")

(define (q-test quotient)
  (test 0 quotient 0 12345678909876532341)
  (test 0 quotient 0 -1235782934075829307)
  (test 2374865902374859023745 quotient 2374865902374859023745 1)
  (test -2374865902374859023745 quotient -2374865902374859023745 1)
  (test 0 quotient 1 13748910785903278450)
  (test 1 quotient 13748910785903278450 13748910785903278449)
  (test 0 quotient 13748910785903278450 13748910785903278451)
  (test -1 quotient -13748910785903278450 13748910785903278449)
  (test 0 quotient -13748910785903278450 13748910785903278451)
  (test -1 quotient 13748910785903278450 -13748910785903278449)
  (test 0 quotient 13748910785903278450 -13748910785903278451)
  (test 1 quotient -13748910785903278450 -13748910785903278449)
  (test 0 quotient -13748910785903278450 -13748910785903278451)
  (test 1 quotient 13748910785903278450 13748910785903278450)
  (test -1 quotient -13748910785903278450 13748910785903278450)
  (test -1 quotient 13748910785903278450 -13748910785903278450)
  (test 1 quotient -13748910785903278450 -13748910785903278450)
  (test (expt 5 64) quotient (expt 5 256) (expt 5 192))
  (test 0 quotient (expt 5 192) (expt 5 256))
  (test 8636168555094444625386351862800399571116000364436281385023703470168591803162427057971507503472288226560547293946149 quotient (expt 5 192) (expt 2 64)))
(q-test quotient)
(q-test (lambda (n1 n2) (let-values ([(q r) (quotient/remainder n1 n2)]) q)))

(define (r-test remainder)
  (test 0 remainder 0 12345678909876532341)
  (test 0 remainder 0 -1235782934075829307)
  (test 0 remainder 2374865902374859023745 1)
  (test 0 remainder -2374865902374859023745 1)
  (test 1 remainder 1 13748910785903278450)
  (test 1 remainder 13748910785903278450 13748910785903278449)
  (test 13748910785903278450 remainder 13748910785903278450 13748910785903278451)
  (test -1 remainder -13748910785903278450 13748910785903278449)
  (test -13748910785903278450 remainder -13748910785903278450 13748910785903278451)
  (test 1 remainder 13748910785903278450 -13748910785903278449)
  (test 13748910785903278450 remainder 13748910785903278450 -13748910785903278451)
  (test -1 remainder -13748910785903278450 -13748910785903278449)
  (test -13748910785903278450 remainder -13748910785903278450 -13748910785903278451)
  (test 0 remainder 13748910785903278450 13748910785903278450)
  (test 0 remainder -13748910785903278450 13748910785903278450)
  (test 0 remainder 13748910785903278450 -13748910785903278450)
  (test 0 remainder -13748910785903278450 -13748910785903278450)
  (test 0 remainder (expt 5 256) (expt 5 192))
  (test (expt 5 192) remainder (expt 5 192) (expt 5 256))
  (test 12241203936672963841 remainder (expt 5 192) (expt 2 64)))
(r-test remainder)
(r-test (lambda (n1 n2) (let-values ([(q r) (quotient/remainder n1 n2)]) r)))

(define (s-test sqrt)
  (test 0 sqrt 0)
  (test 1 sqrt 1)
  (test 2 sqrt 4)
  (test 3 sqrt 9)
  (test (expt 2 64) sqrt (* (expt 2 64) (expt 2 64)))
  (test (expt 13 70) sqrt (* (expt 13 70) (expt 13 70)))
  (test (sub1 (expt 2 200)) sqrt (* (sub1 (expt 2 200)) (sub1 (expt 2 200))))
  (test (expt 2 25) sqrt (expt 2 50))
  (test 1 sqrt 3)
  (test #xffffffff sqrt (sub1 (expt 2 64)))
  (test 2876265888493261300027370452880859375 sqrt (expt 15 62))
  (test #x8f0767e50d4d0c07563bd81f530d36 sqrt (expt 15 61)))
(s-test integer-sqrt)
(s-test (lambda (a) (let-values ([(root rem) (integer-sqrt/remainder a)]) root)))

(define (sr-test sqrt)
  (test 0 sqrt 0)
  (test 0 sqrt 1)
  (test 0 sqrt 4)
  (test 0 sqrt 9)
  (test 0 sqrt (* (expt 2 64) (expt 2 64)))
  (test 0 sqrt (* (expt 13 70) (expt 13 70)))
  (test 0 sqrt (* (sub1 (expt 2 200)) (sub1 (expt 2 200))))
  (test 0 sqrt (expt 2 50))
  (test 2 sqrt 3)
  (test 8589934590 sqrt (sub1 (expt 2 64)))
  (test 0 sqrt (expt 15 62))
  (test 1306106749204831357295958563982718571 sqrt (expt 15 61)))
(sr-test (lambda (a) (let-values ([(root rem) (integer-sqrt/remainder a)]) rem)))

(test 1.7320508075688772 sqrt 3)
(test 4294967296.0 sqrt (sub1 (expt 2 64)))
(test 2876265888493261300027370452880859375 sqrt (expt 15 62))
(test 7.426486590265921e+35 sqrt (expt 15 61))



(test 5.515270307539953e+71 exact->inexact (expt 15 61))
(test -5.515270307539953e+71 exact->inexact (- (expt 15 61)))
(test 1.8446744073709552e+19 exact->inexact (expt 2 64))
(test 1.157920892373162e+77 exact->inexact (expt 2 256))
(test 1.157920892373162e+77 exact->inexact (sub1 (expt 2 256)))

(test 551527030753995340375346347667240734743269800540264151034260072897183744 inexact->exact 5.515270307539953d+71)
(test (expt 2 64) inexact->exact 1.8446744073709552e+19)
(test (- (expt 2 64)) inexact->exact -1.8446744073709552e+19)
(test (expt 2 256) inexact->exact 1.157920892373162d+77)
(test 115792089237316195423570985008687907853269984665640564039457584007913129639936 inexact->exact 1.157920892373162d+77)

#reader "maybe-single.rkt"
(when has-single-flonum?
  (test 521335/89202980794122492566142873090593446023921664 inexact->exact 5.844367f-39)
  (test 5.844367f-39 real->single-flonum (inexact->exact 5.844367f-39))
  (test (real->double-flonum 5.844367f-39) exact->inexact (inexact->exact 5.844367f-39)))

;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(test (integer-bytes->integer #"\1\2" #f) integer-bytes->integer #"\1\2" #f (system-big-endian?))

(define (test-integer-bytes->integer integer-bytes->integer)
  (test #x22 integer-bytes->integer (bytes #x22) #t)
  (test #x22 integer-bytes->integer (bytes #x22) #f)
  (test #xFE integer-bytes->integer (bytes #xFE) #f)
  (test (- #x7E) integer-bytes->integer (bytes #x82) #t)
  (test -1 integer-bytes->integer (bytes #xFF) #t)
  (test 255 integer-bytes->integer (bytes #xFF) #f)

  (test 0 integer-bytes->integer #"\0\0" #t)
  (test -1 integer-bytes->integer #"\377\377" #t)
  (test 65535 integer-bytes->integer #"\377\377" #f)
  ;;
  (test 0 integer-bytes->integer #"\0\0" #t #t)
  (test -1 integer-bytes->integer #"\377\377" #t #t)
  (test 65535 integer-bytes->integer #"\377\377" #f #t)
  (test -256 integer-bytes->integer #"\377\0" #t #t)
  (test -255 integer-bytes->integer #"\377\1" #t #t)
  (test 511 integer-bytes->integer #"\1\377" #t #t)
  (test 513 integer-bytes->integer #"\1\2" #f #f)
  ;;
  (test 0 integer-bytes->integer #"\0\0" #t #f)
  (test -1 integer-bytes->integer #"\377\377" #t #f)
  (test 65535 integer-bytes->integer #"\377\377" #f #f)
  (test 511 integer-bytes->integer #"\377\1" #t #f)
  (test -255 integer-bytes->integer #"\1\377" #t #f)
  (test 258 integer-bytes->integer #"\1\2" #f #t)

  (test 0 integer-bytes->integer #"\0\0\0\0" #t)
  (test -1 integer-bytes->integer #"\377\377\377\377" #t)
  (test 4294967295 integer-bytes->integer #"\377\377\377\377" #f)
  ;;
  (test 0 integer-bytes->integer #"\0\0\0\0" #t #t)
  (test -1 integer-bytes->integer #"\377\377\377\377" #t #t)
  (test 4294967295 integer-bytes->integer #"\377\377\377\377" #f #t)
  (test -16777216 integer-bytes->integer #"\377\0\0\0" #t #t)
  (test 255 integer-bytes->integer #"\0\0\0\377" #t #t)
  ;;
  (test 0 integer-bytes->integer #"\0\0\0\0" #t #f)
  (test -1 integer-bytes->integer #"\377\377\377\377" #t #f)
  (test 4294967295 integer-bytes->integer #"\377\377\377\377" #f #f)
  (test 16777471 integer-bytes->integer #"\377\0\0\1" #t #f)
  (test -16777216 integer-bytes->integer #"\0\0\0\377" #t #f)
  (test -16777215 integer-bytes->integer #"\1\0\0\377" #t #f)

  (test 1835103348 integer-bytes->integer #"matt" #t #t)
  (test 1953784173 integer-bytes->integer #"matt" #t #f)

  (test 0 integer-bytes->integer #"\0\0\0\0\0\0\0\0" #t #t)
  (test -1 integer-bytes->integer #"\377\377\377\377\377\377\377\377" #t #f)
  (test 18446744073709551615 integer-bytes->integer #"\377\377\377\377\377\377\377\377" #f #f)
  (test 4294967295 integer-bytes->integer #"\377\377\377\377\0\0\0\0" #t #f)
  (test -4294967296 integer-bytes->integer #"\0\0\0\0\377\377\377\377" #t #f)
  (test 8589934591 integer-bytes->integer #"\377\377\377\377\1\0\0\0" #t #f)
  (test -4294967295 integer-bytes->integer #"\1\0\0\0\377\377\377\377" #t #f)
  ;;
  (test 0 integer-bytes->integer #"\0\0\0\0\0\0\0\0" #t #f)
  (test -1 integer-bytes->integer #"\377\377\377\377\377\377\377\377" #t #f)
  (test 18446744073709551615 integer-bytes->integer #"\377\377\377\377\377\377\377\377" #f #f)
  (test -4294967296 integer-bytes->integer #"\377\377\377\377\0\0\0\0" #t #t)
  (test 4294967295 integer-bytes->integer #"\0\0\0\0\377\377\377\377" #t #t)
  (test -4294967295 integer-bytes->integer #"\377\377\377\377\0\0\0\1" #t #t)
  (test 8589934591 integer-bytes->integer #"\0\0\0\1\377\377\377\377" #t #t))

(test-integer-bytes->integer integer-bytes->integer)
(test-integer-bytes->integer (lambda (bstr signed? [big-endian? (system-big-endian?)])
                               (integer-bytes->integer (bytes-append #"xxx" bstr)
                                                       signed?
                                                       big-endian?
                                                       3)))
(test-integer-bytes->integer (lambda (bstr signed? [big-endian? (system-big-endian?)])
                               (integer-bytes->integer (bytes-append #"xxx" bstr #"x")
                                                       signed?
                                                       big-endian?
                                                       3
                                                       (+ 3 (bytes-length bstr)))))

(arity-test integer-bytes->integer 2 5)
(err/rt-test (integer-bytes->integer 'ok #t))
(err/rt-test (integer-bytes->integer #"" #t))
(err/rt-test (integer-bytes->integer #"abc" #t))
(err/rt-test (integer-bytes->integer #"abcdefghi" #t))
(err/rt-test (integer-bytes->integer #"abcdefghi" #t #f 0 3))
(err/rt-test (integer-bytes->integer #"abcd" #t #f 1))

;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(test (integer->integer-bytes 42 2 #f) integer->integer-bytes 42 2 #f (system-big-endian?))

(define (test-integer->integer-bytes integer->integer-bytes)
  (test (bytes #x22) integer->integer-bytes #x22 1 #f)
  (test (bytes #x22) integer->integer-bytes #x22 1 #t)
  (test (bytes #xFE) integer->integer-bytes #xFE 1 #f)
  (test (bytes #x82) integer->integer-bytes (- #x7E) 1 #t)
  (test #"\377" integer->integer-bytes -1 1 #t)
  (test #"\200" integer->integer-bytes -128 1 #t)
  (test #"\377" integer->integer-bytes 255 1 #f)

  (test #"\0\0" integer->integer-bytes 0 2 #t)
  (test #"\377\377" integer->integer-bytes -1 2 #t)
  (test #"\377\377" integer->integer-bytes 65535 2 #f)
  ;;
  (test #"\0\0" integer->integer-bytes 0 2 #t #t)
  (test #"\377\377" integer->integer-bytes -1 2 #t #t)
  (test #"\377\377" integer->integer-bytes 65535 2 #f #t)
  (test #"\377\0" integer->integer-bytes -256 2 #t #t)
  (test #"\377\1" integer->integer-bytes -255 2 #t #t)
  (test #"\1\377" integer->integer-bytes 511 2 #t #t)
  (test #"\1\2" integer->integer-bytes 513 2 #f #f)
  ;;
  (test #"\0\0" integer->integer-bytes 0 2 #t #f)
  (test #"\377\377" integer->integer-bytes -1 2 #t #f)
  (test #"\377\377" integer->integer-bytes 65535 2 #f #f)
  (test #"\377\1" integer->integer-bytes 511 2 #t #f)
  (test #"\1\377" integer->integer-bytes -255 2 #t #f)
  (test #"\1\2" integer->integer-bytes 258 2 #f #t)

  (test #"\0\0\0\0" integer->integer-bytes 0 4 #t)
  (test #"\377\377\377\377" integer->integer-bytes -1 4 #t)
  (test #"\377\377\377\377" integer->integer-bytes 4294967295 4 #f)
  ;;
  (test #"\0\0\0\0" integer->integer-bytes 0 4 #t #t)
  (test #"\377\377\377\377" integer->integer-bytes -1 4 #t #t)
  (test #"\377\377\377\377" integer->integer-bytes 4294967295 4 #f #t)
  (test #"\377\0\0\0" integer->integer-bytes -16777216 4 #t #t)
  (test #"\0\0\0\377" integer->integer-bytes 255 4 #t #t)
  ;;
  (test #"\0\0\0\0" integer->integer-bytes 0 4 #t #f)
  (test #"\377\377\377\377" integer->integer-bytes -1 4 #t #f)
  (test #"\377\377\377\377" integer->integer-bytes 4294967295 4 #f #f)
  (test #"\377\0\0\1" integer->integer-bytes 16777471 4 #t #f)
  (test #"\0\0\0\377" integer->integer-bytes -16777216 4 #t #f)
  (test #"\1\0\0\377" integer->integer-bytes -16777215 4 #t #f)

  (test #"matt" integer->integer-bytes 1835103348 4 #t #t)
  (test #"matt" integer->integer-bytes 1953784173 4 #t #f)

  (test #"\0\0\0\0\0\0\0\0" integer->integer-bytes 0 8 #t #t)
  (test #"\377\377\377\377\377\377\377\377" integer->integer-bytes -1 8 #t #f)
  (test #"\377\377\377\377\377\377\377\377" integer->integer-bytes 18446744073709551615 8 #f #f)
  (test #"\377\377\377\377\0\0\0\0" integer->integer-bytes 4294967295 8 #t #f)
  (test #"\0\0\0\0\377\377\377\377" integer->integer-bytes -4294967296 8 #t #f)
  (test #"\377\377\377\377\1\0\0\0" integer->integer-bytes 8589934591 8 #t #f)
  (test #"\1\0\0\0\377\377\377\377" integer->integer-bytes -4294967295 8 #t #f)
  ;;
  (test #"\0\0\0\0\0\0\0\0" integer->integer-bytes 0 8 #t #f)
  (test #"\377\377\377\377\377\377\377\377" integer->integer-bytes -1 8 #t #f)
  (test #"\377\377\377\377\377\377\377\377" integer->integer-bytes 18446744073709551615 8 #f #f)
  (test #"\377\377\377\377\0\0\0\0" integer->integer-bytes -4294967296 8 #t #t)
  (test #"\0\0\0\0\377\377\377\377" integer->integer-bytes 4294967295 8 #t #t)
  (test #"\377\377\377\377\0\0\0\1" integer->integer-bytes -4294967295 8 #t #t)
  (test #"\0\0\0\1\377\377\377\377" integer->integer-bytes 8589934591 8 #t #t))

(test-integer->integer-bytes integer->integer-bytes)
(test-integer->integer-bytes (lambda (num sz signed? [bigend? (system-big-endian?)])
                               (let ([bstr (make-bytes 11 (char->integer #\x))])
                                 (integer->integer-bytes num sz signed? bigend? bstr 3)
                                 (test #"xxx" subbytes bstr 0 3)
                                 (test (make-bytes (- 11 3 sz) (char->integer #\x)) subbytes bstr (+ 3 sz))
                                 (subbytes bstr 3 (+ 3 sz)))))

(arity-test integer->integer-bytes 3 6)
(err/rt-test (integer->integer-bytes 'ack 2 #t))
(err/rt-test (integer->integer-bytes 10 'ack #t))
(err/rt-test (integer->integer-bytes 10 20 #t))
(err/rt-test (integer->integer-bytes 10 2 #t #t 'ack))
(err/rt-test (integer->integer-bytes 10 2 #t #t #"ack")) ; <-- immutable string
(err/rt-test (integer->integer-bytes 256 1 #t) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes -129 1 #t) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes 257 1 #f) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes -1 1 #f) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes 100000 2 #t) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes 65536 2 #f) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes 32768 2 #t) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes -32769 2 #t) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes (expt 2 32) 4 #f) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes (expt 2 31) 4 #t) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes (sub1 (- (expt 2 31))) 4 #t) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes (expt 2 64) 8 #f) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes (expt 2 63) 4 #t) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes (sub1 (- (expt 2 63))) 8 #t) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes 100 4 #t #t (make-bytes 3)) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes 100 2 #t #t (make-bytes 3) 2) exn:application:mismatch?)

(map (lambda (v)
       (let-values ([(n size signed?) (apply values v)])
	 (test n integer-bytes->integer (integer->integer-bytes n size signed? #f) signed? #f)
	 (test n integer-bytes->integer (integer->integer-bytes n size signed? #t) signed? #t)))
     (list
      (list 10 2 #t)

      (list (sub1 (expt 2 16)) 2 #f)
      (list (sub1 (expt 2 15)) 2 #t)
      (list (- (expt 2 15)) 2 #t)

      (list (sub1 (expt 2 32)) 4 #f)
      (list (sub1 (expt 2 31)) 4 #t)
      (list (- (expt 2 31)) 4 #t)

      (list (sub1 (expt 2 64)) 8 #f)
      (list (sub1 (expt 2 63)) 8 #t)
      (list (- (expt 2 63)) 8 #t)))

(let ([s (make-bytes 4)]
      [n (random 10000)])
  (test s integer->integer-bytes n 4 #f #f s)
  (test s integer->integer-bytes n 4 #f #f))

;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Used for comparison after loss of precision in 4-byte conversion
(define (close? a b)
  (or (equal? a b)
      (if (negative? a)
	  (>= (* b 0.999) a (* b 1.001))
	  (<= (* b 0.999) a (* b 1.001)))
      (and (= b +inf.0)
	   (> a 1e38))
      (and (= b -inf.0)
	   (< a -1e38))))

(map (lambda (n)
       (test #t close? n (floating-point-bytes->real (real->floating-point-bytes n 4 #t) #t))
       (test #t close? n (floating-point-bytes->real (real->floating-point-bytes n 4 #f) #f))
       (test n floating-point-bytes->real (real->floating-point-bytes n 8 #t) #t)
       (test n floating-point-bytes->real (real->floating-point-bytes n 8 #f) #f))
     (append
      (list 0.0
	    -0.0
	    +inf.0
	    -inf.0
	    +nan.0
	    1.0
	    0.1
	    1e10)
      (let loop ([n 50])
	(if (zero? n)
	    null
	    (cons (* (if (= 1 (random 2)) 1 -1)
		     (sqrt (/ (random 3000) 3000.0))
		     (expt 2.0 (random 300)))
		  (loop (sub1 n)))))))

(define (there-and-back n)
  (floating-point-bytes->real (real->floating-point-bytes n 8)))

(err/rt-test (there-and-back 1.0+0.0i))
(err/rt-test (there-and-back 100.0+0.0i))
(test 101.0 there-and-back 101)
(test 1e30 there-and-back 1000000000000000000000000000000)
(test 0.5 there-and-back 1/2)

(let ([s (make-bytes 8)]
      [n (expt (add1 (random 100)) (- (random 100)))])
  (test s real->floating-point-bytes n 8 #f s)
  (test s real->floating-point-bytes n 8 #f))

(err/rt-test (real->floating-point-bytes 1 -4))
(err/rt-test (real->floating-point-bytes 1 7))
(err/rt-test (real->floating-point-bytes 1 7000000000000000000000000))
(err/rt-test (real->floating-point-bytes 1+2i 8))
(err/rt-test (real->floating-point-bytes 1.0+2.0i 8))
(err/rt-test (real->floating-point-bytes 1.0 8 #f (make-bytes 7)) exn:application:mismatch?)

;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Check single-flonum coercisons:

#reader "maybe-single.rkt"
(define ((check-single-flonum #:real-only? [real-only? #f]
                              #:integer-only? [integer-only? #f]
                              #:two-arg-real-only? [two-arg-real-only? real-only?]
                              #:arity-one-only? [arity-one-only? #f])
         op)
  (define (single-flonum-ish? op . args)
    (define v (apply op args))
    (and (or (single-flonum? (real-part v))
             (eq? 0 (real-part v)))
         (or (single-flonum? (imag-part v))
             (eq? 0 (imag-part v)))))
  (when (procedure-arity-includes? op 1)
    (test #t single-flonum-ish? op 2.0f0)
    (unless real-only?
      (test #t single-flonum-ish? op 2.0f0+4.0f0i)
      (test #t single-flonum-ish? op 0+4.0f0i)))
  (when (and (procedure-arity-includes? op 2) (not arity-one-only?))
    (test #t single-flonum-ish? op 2.0f0 4.0f0)
    (test #f single-flonum-ish? op 2.0 4.0f0)
    (test #f single-flonum-ish? op 2.0f0 4.0)
    (test #t single-flonum-ish? op 2.0f0 4)
    (test #t single-flonum-ish? op 2 4.0f0)
    (unless integer-only?
      (unless two-arg-real-only? 
        (test #t single-flonum-ish? op 2.0f0 2.0f0+4.0f0i)
        (test #t single-flonum-ish? op 2.0f0 0+4.0f0i)
        (test #f single-flonum-ish? op 2.0f0 2.0+4.0i)
        (test #f single-flonum-ish? op 2.0f0 0+4.0i)
        (test #f single-flonum-ish? op 2.0 2.0f0+4.0f0i)
        (test #f single-flonum-ish? op 2.0 0+4.0f0i))
      (test #t single-flonum-ish? op 2.0f0 0.5f0)
      (test #f single-flonum-ish? op 2.0 0.5f0)
      (test #f single-flonum-ish? op 2.0f0 0.5)
      (test #t single-flonum-ish? op 2.0f0 1/2)
      (test #t single-flonum-ish? op 4/5 0.5f0))))

(when has-single-flonum?

  (map (check-single-flonum)
       (list + - * / 
             add1
             sub1
             sqrt
             expt
             exp
             sin
             cos
             tan
             asin
             acos))

  (map (check-single-flonum #:arity-one-only? #t)
       (list log))

  (map (check-single-flonum #:two-arg-real-only? #t)
       (list atan))

  (map (check-single-flonum #:real-only? #f #:integer-only? #t)
       (list quotient
             remainder
             modulo))

  (map (check-single-flonum #:real-only? #t)
       (list
        abs
        max
        min
        gcd
        lcm
        round
        floor
        ceiling
        truncate)))

;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; This test once trigggered a crash due to an incorrect
;; hard-wired GC declaration for xform:

(when (eq? 'racket (system-type 'vm))
  (define (root n r)
    (expt n (/ 1 r)))
  
  (define (n-digit-has-nth-root? n)
    (not (= (floor (root (expt 10 (- n 1)) n))
            (floor (root (- (expt 10 n) 1) n)))))
  
  (test #t list? (filter n-digit-has-nth-root? (build-list 5000 (lambda (x) (+ x 1))))))

;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; exact->inexact precision on bignums (round-trip and proper rounding)

(define max-53-bit-number (sub1 (arithmetic-shift 1 53)))

(define (check-conversion 53-bit-number)
  ;; Any 53-bit integer fits in a 64-bit floating point:
  (unless (= 53-bit-number (inexact->exact (exact->inexact 53-bit-number)))
    (error 'random-exact->inexact "round-trip failed ~s" 53-bit-number))
  
  ;; The same holds if we shift by up to (- 1023 52):
  (define (check-shift p)
    (define n2 (arithmetic-shift 53-bit-number p))
    (unless (= n2 (inexact->exact (exact->inexact n2)))
      (error 'random-exact->inexact "round-trip of shifted failed ~s" n2)))
  (check-shift (- 1023 52))
  (for ([i 10])
    (check-shift (random (- 1023 52))))
  
  ;; The same holds if we shift by up to (- -1022 52):
  (define (check-div p)
    (define n2 (/ 53-bit-number (arithmetic-shift 1 (- p))))
    (unless (= n2 (inexact->exact (exact->inexact n2)))
      (error 'random-exact->inexact "round-trip of shifted failed ~s" n2)))
  (check-div (- (+ 1022 52)))
  (for ([i 10])
    (check-div (- (random (+ 1022 52)))))
  
  ;; Helper for checking rounding:
  (define (check-random-pairs check-shift-pair)
    (check-shift-pair 1 0)
    (check-shift-pair (- 1023 52 1) 0)
    (check-shift-pair 1 (- 1023 52 2))
    (for ([i 10])
      (define zeros (add1 (random (- 1023 52 3))))
      (define extra (random (- 1023 52 1 zeros)))
      (check-shift-pair zeros extra)))
  
  ;; If we add a zero bit and then a non-zero bit anywhere later,
  ;; conversion to inexact should round down.
  (define (check-shift-plus-bits-to-truncate num-zeros extra-p)
    (define n2 (arithmetic-shift
                (bitwise-ior (arithmetic-shift 53-bit-number (add1 num-zeros))
                             1)
                extra-p))
    (define n3 (inexact->exact (exact->inexact n2)))
    (unless (= n3 (arithmetic-shift 53-bit-number (+ num-zeros 1 extra-p)))
      (error 'random-exact->inexact "truncating round failed ~s ~s ~s" n2 53-bit-number (+ num-zeros 1 extra-p))))
  (check-random-pairs check-shift-plus-bits-to-truncate)
  
  ;; If we add a one bit and then a non-zero bit anywhere later,
  ;; conversion to inexact should round up.
  (unless (= 53-bit-number max-53-bit-number)
    (define (check-shift-plus-bits-to-up num-one-then-zeros extra-p)
      (define n2 (arithmetic-shift
                  (bitwise-ior (arithmetic-shift 
                                (bitwise-ior (arithmetic-shift 53-bit-number 1)
                                             1)
                                num-one-then-zeros)
                               1)
                  extra-p))
      (define n3 (inexact->exact (exact->inexact n2)))
      (unless (= n3 (arithmetic-shift (add1 53-bit-number) (+ num-one-then-zeros 1 extra-p)))
        (error 'random-exact->inexact "round up failed ~s" n2)))
    (check-random-pairs check-shift-plus-bits-to-up))

  ;; If we add a one bit and then only zero bits,
  ;; conversion to inexact should round to even.
  (unless (= 53-bit-number max-53-bit-number)
    (define (check-shift-plus-bits-to-even num-one-then-zeros extra-p)
      (define n2 (arithmetic-shift 
                  (bitwise-ior (arithmetic-shift 53-bit-number 1)
                               1)
                  (+ num-one-then-zeros extra-p)))
      (define n3 (inexact->exact (exact->inexact n2)))
      (unless (= n3 (arithmetic-shift (if (even? 53-bit-number)
                                          53-bit-number
                                          (add1 53-bit-number))
                                      (+ num-one-then-zeros 1 extra-p)))
        (error 'random-exact->inexact "round to even failed ~s" n2)))
    (check-random-pairs check-shift-plus-bits-to-even)))
  
(check-conversion max-53-bit-number)
(for ([i 100])
  (check-conversion
   ;; Random 53-bit number:
   (+ (arithmetic-shift 1 52)
      (arithmetic-shift (random (expt 2 24)) 24)
      (random (expt 2 28)))))

;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Check round-to-even of rational conversion (thanks to Robby)

(let ()
  (define l (floating-point-bytes->real #"\x1a\xd8\x9c\x17\x21\x2e\xfd\x25" #t))
  (define r (floating-point-bytes->real #"\x1a\xd8\x9c\x17\x21\x2e\xfd\x26" #t))
  (test r exact->inexact (/ (+ (inexact->exact l)
                               (inexact->exact r))
                            2)))

;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; exact->inexact precision (thanks to Neil Toronto)

(define (check start end exact-> ->exact >=?)
  (define delta (/ (- end start) 300))
  (for/fold ([prev (exact-> start)]) ([i (in-range start (+ end delta) delta)])
    (define next (exact-> i))
    (test #t >=? next prev)
    (test next exact-> (->exact next))
    next)
  (for/fold ([prev (exact-> start)]) ([i (in-range start (+ end delta) delta)])
    (define next (exact-> (- i)))
    (test #t >=? prev next)
    (test next exact-> (->exact next))
    next)
  (void))

(check #e100000000000000.0 #e100000000000000.1 exact->inexact inexact->exact >=)
(check #e100000000000000.0 #e100000000000000.1 real->double-flonum inexact->exact >=)
(when has-single-flonum?
  (check #e1000000.0 #e1000000.1 real->single-flonum inexact->exact >=))
(when (extflonum-available?)
  (check #e1000000000000000000.0 #e1000000000000000000.1 real->extfl extfl->exact extfl>=))

;; Sanity check
(test 0.14285714285714285 real->double-flonum 1/7)
(test 1.2857142857142858 real->double-flonum 9/7)
;; Cases that real->double-flonum used to get wrong
(test -4882.526517254422 real->double-flonum -13737024017780747/2813507303900)
(test -9.792844933246106e-14 real->double-flonum -1656/16910305547451097)

;; Arbitrary base log
(test (/ (log 5) (log 20)) log 5 20)
(test (/ (log 5) (log -8)) log 5 -8)
(test (/ (log 7) (log 3+5i)) log 7 3+5i)
(test (/ (log -5+2i) (log 12)) log -5+2i 12)

;; Hack to use the "math" package when it's available:
(when (collection-file-path "base.rkt" "math" #:fail (lambda (x) #f))
  (eval
   '(begin
      (require math/base
               math/flonum)

      (define (random-rational)
        (define d (random-bits (+ 1 (random 8192))))
        (cond [(zero? d)  (random-rational)]
              [else
               (* (if (< (random) 0.5) -1 1)
                  (/ (random-bits (+ 1 (random 8192))) d))]))

      (test #t string? "Randomized testing of rational->flonum")
      (for ([_  (in-range 10000)])
        (define ry (random-rational))
        (define y (real->double-flonum ry))  ; this generates rounding errors
        (define e (flulp-error y ry))
        (unless (<= e 0.5)
          (test #t (lambda (e y ry) (<= e 0.5)) e y ry))
        (unless (= e (exact->inexact (inexact->exact e)))
          (test e exact->inexact (inexact->exact e))))

      (define -max (flonum->ordinal -max.0))
      (define +inf (flonum->ordinal +inf.0))
      (define (random-flonum)
        (ordinal->flonum (random-integer -max +inf)))
      
      (test #t string? "Randomized testing of inexact->exact")
      (define xs (list* -max.0 -1.0 -min.0 -0.0 0.0 +min.0 1.0 +max.0
                        (build-list 100000 (λ (_) (random-flonum)))))
      (for ([x (in-list xs)])
        (unless (= x (exact->inexact (inexact->exact x)))
          (test x exact->inexact (inexact->exact x)))))))

;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(report-errs)
